Repository: timothywarner/az500 Branch: main Commit: 6902b2fec1d2 Files: 235 Total size: 11.4 MB Directory structure: gitextract_20_50j8_/ ├── .github/ │ └── workflows/ │ └── check-readme-links.yml ├── .gitignore ├── AZ-500-Teaching-Punchlist.md ├── AZ-500-cert-study-resources.md ├── AZ-500-course-plan.md ├── GETTING-STARTED.md ├── LICENSE ├── README.md ├── az104-README.md ├── az500-objective-domain.md ├── azure-cli.azcli ├── azure-policy.json ├── azure-powershell.ps1 ├── code-samples/ │ ├── README.md │ ├── bicep/ │ │ └── deployment.bicep │ ├── cli/ │ │ └── azure-cli.azcli │ ├── json/ │ │ ├── azure-policy.json │ │ ├── custom-rbac-role.json │ │ └── deployment.json │ ├── kusto/ │ │ └── kusto.kql │ └── powershell/ │ └── azure-powershell.ps1 ├── custom-rbac-role.json ├── deployment.bicep ├── deployment.json ├── docs/ │ ├── CODE_OF_CONDUCT.md │ ├── CONTRIBUTING.md │ └── SECURITY.md ├── images/ │ └── visio/ │ ├── AZ-500.vsdx │ ├── az300-topology.vsdx │ ├── azure-classroom-reference-diagram.vsdx │ └── drawings.vsdx ├── kusto.kql ├── labs/ │ ├── LAB-SETUP.md │ └── README.md ├── scripts/ │ ├── blueprints/ │ │ ├── basic-networking-blueprint/ │ │ │ ├── Artifacts/ │ │ │ │ ├── 7ddd6a5f-4815-4526-aa69-40bbffd263d3.json │ │ │ │ ├── 7ddd6a5f-4815-4526-aa69-40bbffd26cc7.json │ │ │ │ ├── nsg-template.json │ │ │ │ └── vnet-and-subnet-template.json │ │ │ └── Blueprint.json │ │ ├── blueprints-references.txt │ │ ├── blueprints.ps1 │ │ ├── sample-blueprint/ │ │ │ ├── artifacts/ │ │ │ │ ├── policyStorageTags.json │ │ │ │ ├── policyTags.json │ │ │ │ ├── roleContributor.json │ │ │ │ ├── roleOwner.json │ │ │ │ ├── templateStorage.json │ │ │ │ └── templateStorageParams.json │ │ │ ├── blueprint.json │ │ │ └── blueprintAssignment.json │ │ ├── warner-azure-blueprints.pptx │ │ └── warner-azure-blueprints.ps1 │ ├── key-vault.azcli │ ├── powershell/ │ │ ├── Dockerfile.txt │ │ ├── Update-AutomationAzureModulesForAccount.ps1 │ │ ├── aad-pim-powershell.ps1 │ │ ├── app-gateway-e2e-tls.ps1 │ │ ├── application-security-groups.ps1 │ │ ├── azcopy.txt │ │ ├── azure-key-vault-powershell.ps1 │ │ ├── azuresql-database-tde.ps1 │ │ ├── backup-key-vault.ps1 │ │ ├── convert-vhd.ps1 │ │ ├── cosmos-container-rbac.ps1 │ │ ├── create-aks-cluster.ps1 │ │ ├── create-azure-bastion.ps1 │ │ ├── create-key-vault.ps1 │ │ ├── custom-azure-rbac-role.ps1 │ │ ├── custom-rbac-role.ps1 │ │ ├── customscriptextension.ps1 │ │ ├── enable-azuresql-database-tde.ps1 │ │ ├── enforce-tag-value-rg.json │ │ ├── installWebServer.ps1 │ │ ├── linux-vm-ssh-keys.ps1 │ │ ├── managed-storage-account.ps1 │ │ ├── networking.ps1 │ │ ├── password-reset.ps1 │ │ ├── policy-enforce-tag-value-rg.json │ │ ├── powershell-key-vault.ps1 │ │ ├── storage-account.ps1 │ │ ├── taxonomic-tags.ps1 │ │ ├── validate-deploy-arm-template.ps1 │ │ ├── vm-key-vault.parameters.json │ │ ├── vm-key-vault.template.json │ │ ├── vnet-peering.ps1 │ │ └── webjob.ps1 │ └── sql/ │ ├── azure-sql-database-firewall-rules.sql │ ├── azure-sql-row-level-security.sql │ └── azuresql-database-firewall.sql ├── study-resources/ │ ├── AZ-500-Teaching-Punchlist.md │ ├── AZ-500-cert-study-resources.md │ ├── AZ-500-course-plan.md │ └── README.md ├── templates/ │ ├── 101-aci-vnet/ │ │ ├── README.md │ │ ├── azuredeploy.json │ │ ├── azuredeploy.parameters.json │ │ └── metadata.json │ ├── 101-aks/ │ │ ├── .ci_skip │ │ ├── README.md │ │ ├── azuredeploy.json │ │ ├── azuredeploy.parameters.json │ │ └── metadata.json │ ├── 101-application-gateway-v2-autoscale-create/ │ │ ├── README.md │ │ ├── azuredeploy.json │ │ ├── azuredeploy.parameters.json │ │ └── metadata.json │ ├── 101-functions-managed-identity/ │ │ ├── README.md │ │ ├── azuredeploy.json │ │ ├── azuredeploy.parameters.json │ │ └── metadata.json │ ├── 101-storage-account-create/ │ │ ├── README.md │ │ ├── azuredeploy.json │ │ ├── azuredeploy.parameters.json │ │ └── metadata.json │ ├── 101-vm-simple-windows/ │ │ ├── README.md │ │ ├── azuredeploy.json │ │ ├── azuredeploy.parameters.json │ │ └── metadata.json │ ├── 101-webapp-basic-windows/ │ │ ├── README.md │ │ ├── azuredeploy.json │ │ ├── azuredeploy.parameters.json │ │ └── metadata.json │ ├── 201-2-vms-loadbalancer-lbrules/ │ │ ├── README.md │ │ ├── azuredeploy.json │ │ ├── azuredeploy.parameters.json │ │ └── metadata.json │ ├── 201-sql-auditing-server-policy-to-blob-storage/ │ │ ├── README.md │ │ ├── azuredeploy.json │ │ ├── azuredeploy.parameters.json │ │ └── metadata.json │ ├── AZ-300/ │ │ ├── AKS/ │ │ │ ├── AKS.deployproj │ │ │ ├── Deploy-AzureResourceGroup.ps1 │ │ │ ├── Deployment.targets │ │ │ ├── README.md │ │ │ ├── azuredeploy.json │ │ │ └── azuredeploy.parameters.json │ │ ├── AZ-300.sln │ │ ├── App-Gateway/ │ │ │ ├── App-Gateway.deployproj │ │ │ ├── Deploy-AzureResourceGroup.ps1 │ │ │ ├── Deployment.targets │ │ │ ├── README.md │ │ │ ├── azuredeploy.json │ │ │ └── azuredeploy.parameters.json │ │ ├── AppService+Container/ │ │ │ ├── AppService+Container.deployproj │ │ │ ├── Deploy-AzureResourceGroup.ps1 │ │ │ ├── Deployment.targets │ │ │ ├── README.md │ │ │ ├── azuredeploy.json │ │ │ └── azuredeploy.parameters.json │ │ ├── Deploy-AzureResourceGroup.ps1 │ │ ├── Deployment.targets │ │ ├── KeyVault/ │ │ │ ├── Deploy-AzureResourceGroup.ps1 │ │ │ ├── Deployment.targets │ │ │ ├── KeyVault.deployproj │ │ │ ├── README.md │ │ │ ├── azuredeploy.json │ │ │ └── azuredeploy.parameters.json │ │ ├── README.md │ │ ├── VM Copy Loops.deployproj │ │ ├── WebApp+SQL/ │ │ │ ├── Deploy-AzureResourceGroup.ps1 │ │ │ ├── Deployment.targets │ │ │ ├── README.md │ │ │ ├── WebApp+SQL.deployproj │ │ │ ├── azuredeploy.json │ │ │ └── azuredeploy.parameters.json │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── Basic-ACR-AKS-Blueprint/ │ │ ├── Artifacts/ │ │ │ ├── 16985fcd-e84e-4310-8306-45c89bccc429.json │ │ │ ├── 31e3b372-1efb-42e8-ac45-d938d00212d6.json │ │ │ ├── 397ca67f-80f5-4da5-9484-f71ce2f58030.json │ │ │ ├── a369d0c9-ab75-42b2-8677-2adb34f2757c.json │ │ │ ├── d8a78686-485d-4956-96a6-64f305a7f822.json │ │ │ ├── d8c28060-2804-4421-bed1-f61a5f456183.json │ │ │ └── f465a2a1-0e85-439b-a9ac-3dcf94e066cf.json │ │ └── Blueprint.json │ ├── active-directory-new-domain-ha-2-dc/ │ │ ├── .gitignore │ │ ├── DSC/ │ │ │ ├── ConfigureADBDC.ps1 │ │ │ ├── CreateADPDC.ps1 │ │ │ └── PrepareADBDC.ps1 │ │ ├── README.md │ │ ├── azuredeploy.json │ │ ├── azuredeploy.parameters.json │ │ ├── metadata.json │ │ └── nestedtemplates/ │ │ ├── configureADBDC.json │ │ ├── nic.json │ │ ├── vnet-with-dns-server.json │ │ └── vnet.json │ ├── customscriptext.json │ ├── customscriptext.param.json │ ├── docker-containers.azcli │ ├── generative-ai/ │ │ ├── azurecli.azcli │ │ ├── azuredeploy.json │ │ ├── kusto.kql │ │ ├── main.bicep │ │ └── powershell.ps1 │ ├── virtual-network/ │ │ ├── azuredeploy.json │ │ ├── azuredeploy.parameters.json │ │ ├── hub-vnet.bicep │ │ └── vnets-deploy.bicep │ └── ~arm-templates/ │ ├── S2S-VPN/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── app service-cosmos/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── application-gateway/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── azure-sql-aworks/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── bastion/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── container-registry/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── event-hub/ │ │ ├── eventhub.json │ │ └── eventhub.parameters.json │ ├── firewall/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── iot-hub/ │ │ ├── iothub.json │ │ └── iothub.parameters.json │ ├── linux-vm-password/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── linux-vm-ssh/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── load-balancer/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── multiple-vms/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── new-AD-forest/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── private-dns-zone/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ ├── traffic-manager/ │ │ ├── trafficmanager.json │ │ └── trafficmanager.parameters.json │ ├── virtual-network/ │ │ ├── azuredeploy.json │ │ └── azuredeploy.parameters.json │ └── windows-vm-cse/ │ ├── azuredeploy.json │ └── azuredeploy.parameters.json └── warner-AZ500.pptx ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/check-readme-links.yml ================================================ name: Check Markdown Links on: push: branches: - main workflow_dispatch: jobs: check-links: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Check Links 🔍 id: lychee uses: lycheeverse/lychee-action@v1.9.3 with: args: --verbose --no-progress './*.md' fail: true format: markdown output: ./lychee/out.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create Issue From File if: steps.lychee.outputs.exit_code != 0 uses: peter-evans/create-issue-from-file@v4 with: title: Link Checker Report 🔗 content-filepath: ./lychee/out.md labels: report, automated issue body: | A link checker scan has found broken links in the repository's markdown files. ### Files Scanned - All markdown (*.md) files in the root directory ### Results See below for the detailed report of broken links: ================================================ FILE: .gitignore ================================================ # gcc coverage testing tool files *.gcno *.gcda *.gcov ~$warner-AZ500.pptx az500.code-workspace ================================================ FILE: AZ-500-Teaching-Punchlist.md ================================================ # AZ-500 Teaching Punchlist ## Segment 1: Identity and Access (10 AM - 11 AM) - **Manage Entra Identities** - Users, groups, external identities - Entra ID Protection: MFA, passwordless, Conditional Access - Single sign-on (SSO), OAuth, and app registrations - Privileged Identity Management (PIM), custom roles, and permissions ## Segment 2: Secure Storage (11 AM - 12 PM) - **Plan and Implement Storage Security** - Access control: Azure Blob, File, Table, Queue - Protect data: soft delete, versioning, immutable storage - Encryption: BYOK, double encryption, TDE (databases) - Auditing and compliance: Purview and dynamic masking ## Segment 3: Secure Compute (12 PM - 1 PM) - **Plan and Implement Compute Security** - Azure Bastion, Just-in-Time (JIT) VM access - AKS security: network isolation, monitoring, and authentication - Disk encryption: ADE, encryption at host, confidential disk encryption ## Segment 4: Monitoring and Security Operations (1 PM - 2 PM) - **Monitor and Secure Operations** - Microsoft Defender: Secure Score, compliance, and threat protection - Azure Key Vault: manage secrets, certificates, and keys - Azure Monitor: configure and evaluate alerts - Microsoft Sentinel: analytics, incidents, and automation ## Segment 5: Wrap-up and Q&A (2 PM - 3 PM) - **Q&A and Additional Topics** - Recap of key topics: identity, storage, compute, and monitoring - Answer audience questions - Explore real-world use cases and advanced scenarios ================================================ FILE: AZ-500-cert-study-resources.md ================================================ # Exam AZ-500 Certification Study Resources Last updated: March 2024 ## Official Microsoft Learning Resources * [AZ-500 Exam Page](https://learn.microsoft.com/en-us/certifications/exams/az-500) * [Microsoft Learn AZ-500 Learning Paths](https://learn.microsoft.com/en-us/credentials/certifications/azure-security-engineer/) * [Official Microsoft Practice Assessment](https://learn.microsoft.com/en-us/credentials/certifications/azure-security-engineer/practice/assessment) * [Microsoft Security Technical Documentation](https://learn.microsoft.com/en-us/security/) * [Microsoft Security Blog](https://www.microsoft.com/security/blog/) * [Azure Security Center Documentation](https://learn.microsoft.com/en-us/azure/defender-for-cloud/) * [Microsoft Defender for Cloud Documentation](https://learn.microsoft.com/en-us/azure/defender-for-cloud/) * [Microsoft Sentinel Documentation](https://learn.microsoft.com/en-us/azure/sentinel/) ## Hands-on Labs & Practice * [Microsoft Learn Labs](https://learn.microsoft.com/en-us/training/paths/manage-security-operations/) * [Official AZ-500 Lab Exercises](https://microsoftlearning.github.io/AZ-500-AzureSecurityTechnologies/) * [Microsoft Azure Free Account](https://azure.microsoft.com/free/) * [Azure Citadel Security Labs](https://www.azurecitadel.com/security/) * [Azure Log Analytics Query Playground](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial) ## Practice Exams & Test Prep * [MeasureUp AZ-500 Practice Tests](https://www.measureup.com/az-500-microsoft-azure-security-technologies.html) * [Whizlabs AZ-500 Practice Tests](https://www.whizlabs.com/microsoft-azure-certification-az-500/) ## Essential Tools * [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/) * [Azure PowerShell](https://learn.microsoft.com/en-us/powershell/azure/) * [Azure Storage Explorer](https://azure.microsoft.com/features/storage-explorer/) * [Microsoft Entra ID Portal](https://entra.microsoft.com/) * Visual Studio Code Extensions: * [Azure Account](https://marketplace.visualstudio.com/items?itemName=ms-vscode.azure-account) * [Azure Security Center](https://marketplace.visualstudio.com/items?itemName=ms-azuresecurity.vscode-azuresecurity) * [Azure CLI Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.azurecli) * [PowerShell](https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell) ## Security Community Resources * [Microsoft Security Community](https://techcommunity.microsoft.com/t5/security-compliance-and-identity/ct-p/SecurityComplianceIdentity) * [Azure Security Center Community](https://techcommunity.microsoft.com/t5/azure-security-center/bd-p/AzureSecurityCenter) * [Microsoft Security Update Guide](https://msrc.microsoft.com/update-guide/) * [Azure Security Podcast](https://azsecuritypodcast.net/) ## Exam Preparation Tips * Focus on hands-on experience with Azure security features * Practice implementing security controls across different Azure services * Understand identity and access management deeply * Master Azure security tools and monitoring capabilities * Review real-world security scenarios and best practices ================================================ FILE: AZ-500-course-plan.md ================================================ # AZ-500 Crash Course: Key Discussion and Demo Topics ## Course Structure - **Duration:** 5 hours (4 segments of ~1 hour each, 8 min break at the top of each hour) - **Focus:** Concise discussion and demos of core AZ-500 topics - **Style:** Interactive and practical --- ## 🔐 Segment 1: Secure Identity and Access (15-20%) - **🔑 Microsoft Entra Management** - Manage security controls for identity and access - Implement multi-factor authentication (MFA) - Configure Conditional Access policies - Plan and manage resources in Privileged Identity Management - **🗝️ Role Management** - Manage Azure built-in role assignments - Create and manage custom roles - Implement Microsoft Entra Permissions Management - **🔐 Application Access** - Manage access to enterprise applications in Microsoft Entra ID - Configure app registration permission scopes and consent - Manage and use service principals - Configure managed identities for Azure resources --- ## 🌐 Segment 2: Secure Networking (20–25%) - **🔒 Virtual Network Security** - Configure Network Security Groups (NSGs) and Application Security Groups (ASGs) - Manage networks with Azure Virtual Network Manager - Plan and implement user-defined routes (UDRs) - Configure VPN connectivity and peering - Implement Virtual WAN with secured virtual hub - Monitor security with Network Watcher - **🛡️ Private Access** - Plan and implement virtual network Service Endpoints - Configure Private Endpoints and Private Link services - Implement network integration for App Service and Functions - Configure network security for App Service Environment - Secure Azure SQL Managed Instance - **🚀 Public Access Security** - Implement TLS for applications - Configure Azure Firewall and Firewall Manager - Deploy Azure Application Gateway and Azure Front Door - Implement Web Application Firewall (WAF) - Deploy Azure DDoS Protection Standard --- ## 💾 Segment 3: Secure Compute, Storage, and Databases (20–25%) - **🖥️ Compute Security** - Configure remote access with Azure Bastion and just-in-time VM access - Secure Azure Kubernetes Service (AKS) - Configure security monitoring for containers (ACI, ACA) - Manage access to Azure Container Registry (ACR) - Implement disk encryption options - Secure Azure API Management - **🗄️ Storage Security** - Configure access control for storage accounts - Manage storage account access keys - Configure secure access for Azure Files and Blob Storage - Protect data with soft delete, backups, versioning, and immutable storage - Configure Bring Your Own Key (BYOK) - Enable double encryption at the Azure Storage infrastructure level - **📊 Database Security** - Enable Microsoft Entra database authentication - Configure database auditing and dynamic masking - Implement Transparent Data Encryption (TDE) - Configure Azure SQL Database Always Encrypted --- ## 🔍 Segment 4: Secure Azure using Microsoft Defender for Cloud and Microsoft Sentinel (30–35%) - **⚙️ Cloud Governance Policies** - Create and assign Azure Policy initiatives - Configure Key Vault network settings and access control - Manage certificates, secrets, and keys - Configure key rotation - Implement backup/recovery for sensitive data - Configure security controls for asset management - **🛠️ Security Posture Management** - Work with Microsoft Defender for Cloud Secure Score - Assess compliance against security frameworks - Manage compliance standards - Connect hybrid and multi-cloud environments - Implement Microsoft Defender External Attack Surface Management (EASM) - **🔒 Threat Protection** - Enable Microsoft Defender workload protection services - Configure Defender for Servers, Databases, and Storage - Implement agentless scanning for VMs - Configure Defender Vulnerability Management - Connect DevOps security for GitHub, Azure DevOps, and GitLab - **📈 Security Monitoring and Automation** - Manage security alerts in Defender for Cloud - Configure workflow automation - Set up data collection rules (DCRs) in Azure Monitor - Configure Microsoft Sentinel data connectors and analytics - Implement Microsoft Sentinel automation --- ## Resources - [🔗 Microsoft Learn AZ-500 Documentation](https://learn.microsoft.com/en-us/certifications/exams/az-500/) - [🛠️ GitHub for Azure Security](https://github.com/topics/azure-security) - [🎥 Azure Security Demos](https://azure.microsoft.com/en-us/resources/videos/) ### Good luck, and let's secure the cloud! 🚀 ## 🎯 Demo Scenario: Securing a Multi-tier Application Follow along with this scenario to practice key security concepts covered in the course. ### Scenario Overview You're a security engineer at Contoso Ltd, tasked with securing a new three-tier application: - Web frontend (Azure App Service) - API layer (Azure Functions) - Database (Azure SQL) ### 🔄 Implementation Steps #### 1. Identity & Access Setup (30 mins) - Configure Microsoft Entra authentication for the web app - Set up managed identities for service-to-service communication - Implement Conditional Access policy for admin access - Configure Privileged Identity Management for just-in-time admin access #### 2. Network Security (30 mins) - Create network isolation using VNets, NSGs, and ASGs - Implement Private Endpoints for the database - Set up Azure Application Gateway with WAF - Configure Azure Front Door with CDN #### 3. Data Protection (30 mins) - Enable TDE and Always Encrypted for sensitive data - Configure Key Vault with RBAC and network restrictions - Implement immutable storage and soft delete - Configure double encryption for storage #### 4. Security Monitoring & Protection (30 mins) - Set up Microsoft Defender for Cloud workload protections - Configure Microsoft Sentinel data connectors and analytics rules - Create automation workflows for common security incidents - Implement vulnerability scanning and management ### 🎯 Success Criteria - ✅ All services use managed identities for authentication - ✅ Private network connectivity between services - ✅ All sensitive data encrypted at rest and in transit - ✅ Comprehensive detection and response capabilities ## Additional Resources ### 🔨 Practice Labs - [Azure Security Labs on Microsoft Learn](https://learn.microsoft.com/en-us/certifications/exams/az-500) - [Whizlabs AZ-500 Hands-on Labs](https://www.whizlabs.com/blog/top-azure-hands-on-labs/) - [Azure GOAT - Vulnerable Azure Environment for Practice](https://github.com/Akriti-S/AzGOAT) - [425Show Secure Azure Function Samples](https://github.com/425show/SecureAzureFunctionMiW) ### 📚 Documentation - [Azure Security Best Practices](https://learn.microsoft.com/en-us/azure/security/fundamentals/best-practices-and-patterns) - [Microsoft Security Documentation](https://learn.microsoft.com/en-us/security/) - [Azure Architecture Center - Security](https://learn.microsoft.com/en-us/azure/architecture/framework/security/overview) ### 🎥 Video Resources - [Microsoft Security YouTube Channel](https://www.youtube.com/c/MicrosoftSecurity) - [Azure Security Center in Action](https://www.youtube.com/playlist?list=PLLasX02E8BPBxGouWlJV-u_XVcXfkdscl) ================================================ FILE: GETTING-STARTED.md ================================================ # Getting Started with AZ-500 Course Materials Welcome to the AZ-500 Microsoft Azure Security Technologies Crash Course! This guide will help you navigate the repository structure and make the most of these learning resources. ## Repository Structure This repository is organized into several key directories: - **[code-samples/](code-samples/)** - Security-focused code examples in Bicep, JSON, PowerShell, CLI, and KQL - **[study-resources/](study-resources/)** - Additional study materials and exam preparation guides - **[labs/](labs/)** - Hands-on lab exercises to practice security implementations - **[images/](images/)** - Diagrams and visual aids for security concepts - **[templates/](templates/)** - ARM templates and deployment examples - **[scripts/](scripts/)** - Utility scripts for security configurations ## How to Use This Repository ### For Self-Study 1. Start with the [main README](README.md) to get an overview of exam topics and resources 2. Review the [study resources](study-resources/) for targeted learning materials 3. Practice with the [code samples](code-samples/) to understand implementation details 4. Complete the [labs](labs/) to gain hands-on experience ### For Instructors 1. Follow the [course plan](study-resources/AZ-500-course-plan.md) for session structure 2. Use the [teaching punchlist](study-resources/AZ-500-Teaching-Punchlist.md) for key topics 3. Leverage code samples for in-class demonstrations 4. Assign labs for student practice ## Setting Up Your Environment To get the most from these materials, set up your environment with: 1. **Azure Subscription** - [Free account](https://azure.microsoft.com/en-us/free/) or paid subscription 2. **Development Tools**: - [Visual Studio Code](https://code.visualstudio.com/) - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) - [PowerShell 7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell) with [Az module](https://learn.microsoft.com/en-us/powershell/azure/install-az-ps) - [Git](https://git-scm.com/downloads) 3. **VS Code Extensions**: - Azure Account - Azure CLI Tools - Bicep - PowerShell ## Learning Path Recommendation For the most effective learning experience: 1. **Week 1**: Identity and Access Management - Review Microsoft Learn modules on identity - Complete identity-related labs - Practice with Azure RBAC examples 2. **Week 2**: Platform Protection - Study network security fundamentals - Work through compute security labs - Implement container security samples 3. **Week 3**: Security Operations - Configure Azure Defender for Cloud - Set up Azure Sentinel - Practice with security monitoring 4. **Week 4**: Data and Application Security - Implement storage security - Configure database security - Work with Azure Key Vault 5. **Final Week**: Exam Preparation - Take practice tests - Review areas of weakness - Complete comprehensive labs ## Getting Help If you have questions or need assistance: - Review the [Microsoft Learn AZ-500 path](https://learn.microsoft.com/en-us/training/courses/az-500t00) - Join the [Microsoft Security Community](https://techcommunity.microsoft.com/t5/security-compliance-and-identity/ct-p/SecurityComplianceandIdentity) - Review Microsoft documentation for specific services Good luck with your Azure security learning journey! ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2021, Tim Warner Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Exam AZ-500: Microsoft Azure Security Technologies Crash Course AZ-500 Course Cover Welcome to the training hub for preparing for the **AZ-500 Microsoft Azure Security Technologies Exam**. Whether you're aiming for certification or deepening your Azure security knowledge, this guide is packed with the best tools, links, and tips to set you up for success. 👉 **New to this repo?** Check out the [Getting Started Guide](GETTING-STARTED.md) for navigation help! 📋 **Looking for the course plan?** View the [AZ-500 Crash Course Plan](AZ-500-course-plan.md)! *Last updated: March 18, 2025* --- ## 📬 **Contact Information** - **[Website](https://techtrainertim.com)** - **[GitHub](https://github.com/timothywarner)** - **[LinkedIn](https://www.linkedin.com/in/timothywarner/)** - **[YouTube Channel](https://www.youtube.com/channel/UCim7PFtynyPuzMHtbNyYOXA)** - **[Bluesky](https://bsky.app/profile/techtrainertim.bsky.social)** - **[Mastodon](https://mastodon.social/@techtrainertim)** --- ## 📆 **Course Plan Overview** This crash course is structured into 4 segments, each approximately 1 hour: 1. **Secure Identity and Access (15-20%)** - Microsoft Entra ID management, MFA, Conditional Access - Role assignments, custom roles, Privileged Identity Management - Application access and managed identities 2. **Secure Networking (20-25%)** - NSGs, ASGs, Virtual Network Manager, UDRs - Private access via Service Endpoints and Private Link - Public access security with Azure Firewall, Front Door, WAF 3. **Secure Compute, Storage, and Databases (20-25%)** - VM and container security (AKS, ACI, ACA) - Storage security, access control, and encryption - SQL Database and Managed Instance security 4. **Defender for Cloud and Microsoft Sentinel (30-35%)** - Cloud governance policies and Key Vault - Security posture management with Defender for Cloud - Threat protection and security monitoring 💡 **See the full [detailed course plan](AZ-500-course-plan.md) for complete information!** --- ## 📋 **Exam Objective Domain** *Skills measured as of January 31, 2025* ### Skills at a Glance - **Secure identity and access** (15–20%) - **Secure networking** (20–25%) - **Secure compute, storage, and databases** (20–25%) - **Secure Azure using Microsoft Defender for Cloud and Microsoft Sentinel** (30–35%) ### Audience Profile As an Azure security engineer, you implement, manage, and monitor security for resources in Azure, multi-cloud, and hybrid environments as part of an end-to-end infrastructure. You implement and manage security components and configurations using Microsoft Defender for Cloud and other tools, ensuring infrastructure aligns with standards and best practices such as the Microsoft Cloud Security Benchmark (MCSB). #### Your responsibilities include: - Managing security posture - Implementing threat protection - Identifying and remediating vulnerabilities - Implementing regulatory compliance controls #### Required experience: - Practical experience in administration of Microsoft Azure and hybrid environments - Strong familiarity with Microsoft Entra ID, as well as compute, network, and storage in Azure ### Detailed Skill Outline #### 1. Secure Identity and Access (15–20%) ##### 1.1 Manage security controls for identity and access - Manage Azure built-in role assignments - Manage custom roles, including Azure roles and Microsoft Entra roles - Implement and manage Microsoft Entra Permissions Management - Plan and manage Azure resources in Microsoft Entra Privileged Identity Management, including settings and assignments - Implement multi-factor authentication (MFA) for access to Azure resources - Implement Conditional Access policies for cloud resources in Azure ##### 1.2 Manage Microsoft Entra application access - Manage access to enterprise applications in Microsoft Entra ID, including OAuth permission grants - Manage Microsoft Entra app registrations - Configure app registration permission scopes - Manage app registration permission consent - Manage and use service principals - Manage managed identities #### 2. Secure Networking (20–25%) ##### 2.1 Plan and implement security for virtual networks - Plan and implement Network Security Groups (NSGs) and Application Security Groups (ASGs) - Manage virtual networks by using Azure Virtual Network Manager - Plan and implement user-defined routes (UDRs) - Plan and implement Virtual Network peering or VPN gateway - Plan and implement Virtual WAN, including secured virtual hub - Secure VPN connectivity, including point-to-site and site-to-site - Implement encryption over ExpressRoute - Configure firewall settings on Azure resources - Monitor network security by using Network Watcher ##### 2.2 Plan and implement security for private access to Azure resources - Plan and implement virtual network Service Endpoints - Plan and implement Private Endpoints - Plan and implement Private Link services - Plan and implement network integration for Azure App Service and Azure Functions - Plan and implement network security configurations for an App Service Environment (ASE) - Plan and implement network security configurations for an Azure SQL Managed Instance ##### 2.3 Plan and implement security for public access to Azure resources - Plan and implement Transport Layer Security (TLS) to applications, including Azure App Service and API Management - Plan, implement, and manage an Azure Firewall, including Azure Firewall Manager and firewall policies - Plan and implement an Azure Application Gateway - Plan and implement an Azure Front Door, including Content Delivery Network (CDN) - Plan and implement a Web Application Firewall (WAF) - Recommend when to use Azure DDoS Protection Standard #### 3. Secure Compute, Storage, and Databases (20–25%) ##### 3.1 Plan and implement advanced security for compute - Plan and implement remote access to virtual machines, including Azure Bastion and just-in-time (JIT) - Configure network isolation for Azure Kubernetes Service (AKS) - Secure and monitor AKS - Configure authentication for AKS - Configure security monitoring for Azure Container Instances (ACIs) - Configure security monitoring for Azure Container Apps (ACAs) - Manage access to Azure Container Registry (ACR) - Configure disk encryption, including Azure Disk Encryption (ADE), encryption at host, and confidential disk encryption - Recommend security configurations for Azure API Management ##### 3.2 Plan and implement security for storage - Configure access control for storage accounts - Manage storage account access keys - Select and configure an appropriate method for access to Azure Files - Select and configure an appropriate method for access to Azure Blob Storage - Select and configure appropriate methods for protecting against data security threats, including soft delete, backups, versioning, and immutable storage - Configure Bring your own key (BYOK) - Enable double encryption at the Azure Storage infrastructure level ##### 3.3 Plan and implement security for Azure SQL Database and Azure SQL Managed Instance - Enable Microsoft Entra database authentication - Enable database auditing - Plan and implement dynamic masking - Implement Transparent Data Encryption (TDE) - Recommend when to use Azure SQL Database Always Encrypted #### 4. Secure Azure using Microsoft Defender for Cloud and Microsoft Sentinel (30–35%) ##### 4.1 Implement and manage enforcement of cloud governance policies - Create, assign, and interpret policies and initiatives in Azure Policy - Configure Azure Key Vault network settings - Configure access to Key Vault, including vault access policies and Azure Role Based Access Control - Manage certificates, secrets, and keys - Configure key rotation - Perform backup and recovery of certificates, secrets, and keys - Implement security controls to protect backups - Implement security controls for asset management ##### 4.2 Manage security posture by using Microsoft Defender for Cloud - Identify and remediate security risks by using the Microsoft Defender for Cloud Secure Score and Inventory - Assess compliance against security frameworks by using Microsoft Defender for Cloud - Manage compliance standards in Microsoft Defender for Cloud - Add custom standards to Microsoft Defender for Cloud - Connect hybrid cloud and multi-cloud environments to Microsoft Defender for Cloud, including Amazon Web Services (AWS) and Google Cloud Platform (GCP) - Implement and use Microsoft Defender External Attack Surface Management (EASM) ##### 4.3 Configure and manage threat protection by using Microsoft Defender for Cloud - Enable workload protection services in Microsoft Defender for Cloud - Configure Microsoft Defender for Servers, Microsoft Defender for Databases, and Microsoft Defender for Storage - Implement and manage agentless scanning for virtual machines in Microsoft Defender for Servers - Implement and manage Microsoft Defender Vulnerability Management for Azure virtual machines - Connect to and configure settings in Microsoft Defender for Cloud DevOps Security, including GitHub, Azure DevOps, and GitLab ##### 4.4 Configure and manage security monitoring and automation solutions - Manage and respond to security alerts in Microsoft Defender for Cloud - Configure workflow automation by using Microsoft Defender for Cloud - Monitor network security events and performance data by configuring data collection rules (DCRs) in Azure Monitor - Configure data connectors in Microsoft Sentinel - Enable analytics rules in Microsoft Sentinel - Configure automation in Microsoft Sentinel --- ## 🚀 **The Good Stuff: Must-Have AZ-500 Resources** - [AZ-500 Exam Page](https://learn.microsoft.com/en-us/certifications/exams/az-500) - [AZ-500 Study Guide (2025)](https://learn.microsoft.com/en-us/credentials/certifications/resources/study-guides/az-500) - [Exam Registration (Microsoft/Pearson VUE)](https://learn.microsoft.com/en-us/credentials/certifications/schedule-through-pearson-vue?examUid=exam.AZ-500) - [AZ-500 Free Practice Assessment](https://learn.microsoft.com/en-us/credentials/certifications/azure-security-engineer/practice/assessment?assessment-type=practice) - [Microsoft Learning AZ-500 Labs](https://microsoftlearning.github.io/AZ500-AzureSecurityTechnologies/) - [Official Microsoft Learning Path](https://learn.microsoft.com/en-us/training/courses/az-500t00) - [MeasureUp AZ-500 Practice Exams](https://www.measureup.com/az-500-microsoft-azure-security-technologies.html) --- ## 📚 **Microsoft Learn Paths** Structured learning paths to master all exam skills: - [Manage identity and access](https://learn.microsoft.com/en-us/training/paths/manage-identity-access/) - [Implement platform protection](https://learn.microsoft.com/en-us/training/paths/implement-platform-protection/) - [Manage security operations](https://learn.microsoft.com/en-us/training/paths/manage-security-operations/) - [Secure Azure services and workloads](https://learn.microsoft.com/en-us/training/paths/secure-azure-services-workloads/) - [Configure security for hybrid environments](https://learn.microsoft.com/en-us/training/paths/configure-security-for-hybrid-environments/) - [Microsoft Defender for Cloud Implementation](https://learn.microsoft.com/en-us/training/paths/implement-microsoft-defender-for-cloud/) --- ## 🛡️ **Security Best Practices** Expert guidance for implementing robust Azure security: ### Identity & Access Management - [Microsoft Entra ID documentation](https://learn.microsoft.com/en-us/entra/identity/) - [Azure RBAC documentation](https://learn.microsoft.com/en-us/azure/role-based-access-control/) - [Privileged Identity Management](https://learn.microsoft.com/en-us/entra/id-governance/privileged-identity-management/) ### Data Protection - [Microsoft Purview documentation](https://learn.microsoft.com/en-us/purview/) - [Azure Key Vault documentation](https://learn.microsoft.com/en-us/azure/key-vault/) - [Azure Storage Security](https://learn.microsoft.com/en-us/azure/storage/common/storage-security-guide) ### Network Security - [Azure DDoS Protection](https://learn.microsoft.com/en-us/azure/ddos-protection/) - [Azure Network Security](https://learn.microsoft.com/en-us/azure/security/fundamentals/network-overview) - [Azure Firewall documentation](https://learn.microsoft.com/en-us/azure/firewall/) --- ## 🔧 **Your Toolkit** Essential tools to follow along and practice efficiently: ### VS Code Extensions - [Security IntelliSense](https://marketplace.visualstudio.com/items?itemName=azsdktm.SecurityIntelliSense) - [Snyk Security](https://marketplace.visualstudio.com/items?itemName=snyk-security.snyk-vulnerability-scanner) - [Azure Account](https://marketplace.visualstudio.com/items?itemName=ms-vscode.azure-account) ### PowerShell Modules - [Az.Security](https://www.powershellgallery.com/packages/Az.Security) - [Az.SecurityInsights](https://www.powershellgallery.com/packages/Az.SecurityInsights) - [Az.KeyVault](https://www.powershellgallery.com/packages/Az.KeyVault) - [Microsoft.PowerShell.SecretManagement](https://www.powershellgallery.com/packages/Microsoft.PowerShell.SecretManagement) ### Dev Tools - [PowerShell 7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell) - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) - [GitHub CLI](https://cli.github.com/) - [Azure PowerShell Module](https://learn.microsoft.com/en-us/powershell/azure/install-az-ps) --- ## 💻 **Hands-on Labs & Practice** Learn through hands-on experience: - **[Lab Environment Setup Guide](labs/LAB-SETUP.md)** - Start here to prepare for labs! - [Microsoft Security Assessment](https://www.microsoft.com/en-us/security/business/security-assessment) - [Microsoft Defender for Cloud Workflow Automation](https://learn.microsoft.com/en-us/azure/defender-for-cloud/workflow-automation) - [Microsoft Secure Score](https://security.microsoft.com/securescore) - [Attack Surface Reduction Rules](https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/attack-surface-reduction) - [Azure Free Account](https://azure.microsoft.com/en-us/free/) - [Microsoft Learn Sandbox Environments](https://learn.microsoft.com/en-us/training/modules/describe-azure-compute-networking-services/4-exercise-configure-network-access) --- ## ✍️ **Practice Tests & Exam Prep** Validate your knowledge before the real exam: - [Microsoft Free Practice Assessment](https://learn.microsoft.com/en-us/credentials/certifications/azure-security-engineer/practice/assessment?assessment-type=practice) - [MeasureUp AZ-500](https://www.measureup.com/az-500-microsoft-azure-security-technologies.html) - [Udemy Practice Tests](https://www.udemy.com/topic/microsoft-az-500/) --- ## 🎓 **Related Certifications** Expand your Microsoft security credentials: ### Microsoft Security Certifications - [SC-100: Microsoft Cybersecurity Architect](https://learn.microsoft.com/en-us/credentials/certifications/cybersecurity-architect-expert/) - [SC-200: Microsoft Security Operations Analyst](https://learn.microsoft.com/en-us/credentials/certifications/security-operations-analyst/) - [SC-300: Microsoft Identity and Access Administrator](https://learn.microsoft.com/en-us/credentials/certifications/identity-and-access-administrator/) - [SC-400: Microsoft Information Protection Administrator](https://learn.microsoft.com/en-us/credentials/certifications/information-protection-administrator/) ### Industry Certifications - CompTIA Security+ - CISSP (Certified Information Systems Security Professional) - CCSP (Certified Cloud Security Professional) - CISM (Certified Information Security Manager) --- ## 💸 **Exam Discounts and Registration Info** - [Microsoft Certification Special Offers](https://learn.microsoft.com/en-us/certifications/deals) - [About Online Exams](https://learn.microsoft.com/en-us/credentials/certifications/online-exams) - [Certification Policies and FAQs](https://learn.microsoft.com/en-us/credentials/certifications/certification-exam-policies) --- ## 🎥 **Tim's Helper Videos** - [Exam Registration Walkthrough](https://www.youtube.com/watch?v=FOFWbSYbbVI) - [Online Testing Tips](https://www.youtube.com/watch?v=myf6r5nulj0) --- ## 🛡️ **2025 Security Focus Areas** ### Zero Trust Security - [Microsoft Zero Trust Implementation Guide](https://learn.microsoft.com/en-us/security/zero-trust/) - [Azure Zero Trust Network Architecture](https://learn.microsoft.com/en-us/security/zero-trust/azure-infrastructure) - [Zero Trust Deployment Center](https://learn.microsoft.com/en-us/security/zero-trust/deploy/) ### Cloud-Native Security - [Microsoft Entra Workload ID](https://learn.microsoft.com/en-us/entra/workload-id/) - [Azure Container Apps Security](https://learn.microsoft.com/en-us/azure/container-apps/security-concept) - [Azure Kubernetes Service (AKS) Security](https://learn.microsoft.com/en-us/azure/aks/concepts-security) ### AI Security & Governance - [Azure OpenAI Service Security](https://learn.microsoft.com/en-us/azure/ai-services/openai/security) - [Responsible AI Guidelines](https://learn.microsoft.com/en-us/azure/ai-services/responsible-ai-standards) - [AI Security Best Practices](https://learn.microsoft.com/en-us/security/ai-security/) --- ## 📱 **Community & Support** Connect with security professionals: - [Microsoft Security Community](https://techcommunity.microsoft.com/t5/security-compliance-and-identity/ct-p/SecurityComplianceandIdentity) - [Azure Security Podcast](https://azsecuritypodcast.net/) - [Microsoft Security Blog](https://www.microsoft.com/security/blog/) - [Microsoft Defender for Cloud GitHub Repository](https://github.com/Azure/Microsoft-Defender-for-Cloud) - [Microsoft Security YouTube Channel](https://www.youtube.com/@MSFTSecurity) --- This README is designed for maximum utility and easy navigation. If you have suggestions or corrections, feel free to reach out via the contact information above. Best of luck on your AZ-500 journey! ================================================ FILE: az104-README.md ================================================ # Tim Warner's AZ-104 Study Resources AZ-104 Course Cover Welcome to the ultimate resource hub for preparing for the **AZ-104 Microsoft Azure Administrator Exam**. Whether you're aiming for certification or deepening your Azure knowledge, this guide is packed with the best tools, links, and tips to set you up for success. --- ## 📬 **Contact Information** - **[Email](mailto:timothywarner316@gmail.com)** - **[LinkedIn](https://www.linkedin.com/in/timothywarner/)** - **[YouTube Channel](https://www.youtube.com/channel/UCim7PFtynyPuzMHtbNyYOXA)** - **[Website](https://techtrainertim.com)** - **[Bluesky](https://bsky.app/profile/techtrainertim.bsky.social)** - **[Mastodon](https://mastodon.social/@techtrainertim)** --- ## 🚀 **The Good Stuff: Must-Have AZ-104 Resources** - [AZ-104 Exam Page](https://learn.microsoft.com/en-us/certifications/exams/az-104) - [AZ-104 Skills Measured](https://learn.microsoft.com/en-us/credentials/certifications/resources/study-guides/az-104) - [Exam Registration (Microsoft/Pearson VUE)](https://learn.microsoft.com/en-us/credentials/certifications/schedule-through-pearson-vue?examUid=exam.AZ-104&examUrl=https%3A%2F%2Flearn.microsoft.com%2Fcredentials%2Fcertifications) - [MeasureUp AZ-104 Practice Exams](https://www.measureup.com/microsoft-practice-test-az-104-microsoft-azure-administrator.html) - [Microsoft Learn AZ-104 Learning Path](https://learn.microsoft.com/en-us/training/courses/az-104t00/) - [Azure Free Account Signup](https://azure.microsoft.com/en-us/pricing/purchase-options/azure-account) - [Pearson CertPREP AZ-104 Training Labs](https://govstore.pearsonvue.com/certprep-microsoft-exam-az-104/p/CLC-AZ104-PVUE) --- ## 📘 **Conceptual Knowledge** These resources build your understanding of Azure fundamentals and exam concepts: - [Azure Documentation](https://docs.microsoft.com/en-us/azure/) - [Azure Architecture Center](https://docs.microsoft.com/en-us/azure/architecture/) - [Azure Quickstart Templates](https://azure.microsoft.com/en-us/resources/templates/) - [Azure SDKs and Tools](https://azure.microsoft.com/en-us/downloads/) - [Sam Cogan ARM Tutorial](https://www.youtube.com/watch?v=9EpBiud48Ao&t=1s) - [Adam Marczak ARM Tutorials](https://www.youtube.com/watch?v=Ge_Sp-1lWZ4&t=916s) - [Azure Bicep Overview](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview) - [AZ-104 Class Topology](https://lucid.app/lucidchart/5b4214cf-b00b-400d-80ff-c15572f57904/view?page=0_0#) --- ## 🛠 **Your Toolkit** Essential tools to follow along and practice efficiently: - **[Visual Studio Code](https://code.visualstudio.com/)** Recommended extensions: - [PowerShell](https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell) - [Azure Account](https://marketplace.visualstudio.com/items?itemName=ms-vscode.azure-account) - [ARM Tools](https://marketplace.visualstudio.com/items?itemName=msazurermtools.azurerm-vscode-tools) - [Azure CLI Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.azurecli) - [Bicep](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep) - [PowerShell 7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell) - [Azure PowerShell Module](https://learn.microsoft.com/en-us/powershell/azure/install-az-ps) - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) - [Azure Storage Explorer](https://azure.microsoft.com/en-us/features/storage-explorer/) - [AzCopy](https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-v10) --- ## 🛡 **Practical Application** Learn through hands-on labs and live environments: - [Azure Free Account](https://azure.microsoft.com/en-us/free/) - [Microsoft Learn: Azure Administrator Path](https://docs.microsoft.com/en-us/learn/browse/?roles=administrator) - [Azure Citadel](https://azurecitadel.com/) - [AZ-104 Microsoft Official Curriculum Labs](https://github.com/MicrosoftLearning/AZ-104-MicrosoftAzureAdministrator) - [Azure Bicep Playground](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/playground) - [Azure Log Analytics Demo Environment](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-demo-environment) --- ## 📑 **Practice Exams** - [Microsoft Free Practice Assessments](https://learn.microsoft.com/en-us/certifications/practice-assessments-for-microsoft-certifications) - [MeasureUp Practice Exams](https://www.measureup.com/az-104-microsoft-azure-administrator.html) --- ## 💸 **Exam Discounts and Registration Info** - [Microsoft Certification Special Offers](https://learn.microsoft.com/en-us/certifications/deals) - [AZ-104 Exam Registration](https://learn.microsoft.com/en-us/credentials/certifications/exams/az-104) - [About Online Exams](https://learn.microsoft.com/en-us/credentials/certifications/online-exams) - [Certification Policies and FAQs](https://learn.microsoft.com/en-us/credentials/certifications/certification-exam-policies) - [Microsoft Certification Exam Policies](https://learn.microsoft.com/en-us/certifications/certification-exam-policies) --- ## 🎥 **Tim's Helper Videos** - [Exam Registration Walkthrough](https://www.youtube.com/watch?v=FOFWbSYbbVI) - [Online Testing Tips](https://www.youtube.com/watch?v=myf6r5nulj0&feature=youtu.be) --- This README is designed for maximum utility and easy navigation. If you have suggestions or corrections, feel free to reach out via the contact information above. Best of luck on your AZ-104 journey! ================================================ FILE: az500-objective-domain.md ================================================ # Exam AZ-500: Microsoft Azure Security Technologies ![Microsoft Azure Security](images/az500-cover-slide-final.png) ## Exam Information **Skills measured as of January 31, 2025** --- ## 🎯 Audience Profile As the Azure security engineer, you implement, manage, and monitor security for resources in Azure, multi-cloud, and hybrid environments as part of an end-to-end infrastructure. You implement and manage security components and configurations by using Microsoft Defender for Cloud and other tools. You ensure that the infrastructure aligns with standards and best practices such as the Microsoft Cloud Security Benchmark (MCSB). ### Your responsibilities include: - ✅ Managing the security posture - ✅ Implementing threat protection - ✅ Identifying and remediating vulnerabilities - ✅ Implementing regulatory compliance controls for Azure infrastructure including identity and access, network, compute, storage, data, applications, asset management, backup and recovery, and DevOps security As an Azure security engineer, you work with architects, administrators, and developers to plan and implement solutions that meet security and compliance requirements. You may also collaborate with security operations in responding to security incidents in Azure. ### Required Experience - Practical experience in administration of Microsoft Azure and hybrid environments - Strong familiarity with Microsoft Entra ID, as well as compute, network, and storage in Azure --- ## 📊 Skills at a Glance | Skill Area | Weight | |------------|--------| | Secure identity and access | 15–20% | | Secure networking | 20–25% | | Secure compute, storage, and databases | 20–25% | | Secure Azure using Microsoft Defender for Cloud and Microsoft Sentinel | 30–35% | --- ## 🔐 Detailed Skills Outline ### 1. Secure Identity and Access (15–20%) #### 1.1 Manage Security Controls for Identity and Access - Manage Azure built-in role assignments - Manage custom roles, including Azure roles and Microsoft Entra roles - Implement and manage Microsoft Entra Permissions Management - Plan and manage Azure resources in Microsoft Entra Privileged Identity Management, including settings and assignments - Implement multi-factor authentication (MFA) for access to Azure resources - Implement Conditional Access policies for cloud resources in Azure #### 1.2 Manage Microsoft Entra Application Access - Manage access to enterprise applications in Microsoft Entra ID, including OAuth permission grants - Manage Microsoft Entra app registrations - Configure app registration permission scopes - Manage app registration permission consent - Manage and use service principals - Manage managed identities --- ### 2. Secure Networking (20–25%) #### 2.1 Plan and Implement Security for Virtual Networks - Plan and implement Network Security Groups (NSGs) and Application Security Groups (ASGs) - Manage virtual networks by using Azure Virtual Network Manager - Plan and implement user-defined routes (UDRs) - Plan and implement Virtual Network peering or VPN gateway - Plan and implement Virtual WAN, including secured virtual hub - Secure VPN connectivity, including point-to-site and site-to-site - Implement encryption over ExpressRoute - Configure firewall settings on Azure resources - Monitor network security by using Network Watcher #### 2.2 Plan and Implement Security for Private Access to Azure Resources - Plan and implement virtual network Service Endpoints - Plan and implement Private Endpoints - Plan and implement Private Link services - Plan and implement network integration for Azure App Service and Azure Functions - Plan and implement network security configurations for an App Service Environment (ASE) - Plan and implement network security configurations for an Azure SQL Managed Instance #### 2.3 Plan and Implement Security for Public Access to Azure Resources - Plan and implement Transport Layer Security (TLS) to applications, including Azure App Service and API Management - Plan, implement, and manage an Azure Firewall, including Azure Firewall Manager and firewall policies - Plan and implement an Azure Application Gateway - Plan and implement an Azure Front Door, including Content Delivery Network (CDN) - Plan and implement a Web Application Firewall (WAF) - Recommend when to use Azure DDoS Protection Standard --- ### 3. Secure Compute, Storage, and Databases (20–25%) #### 3.1 Plan and Implement Advanced Security for Compute - Plan and implement remote access to virtual machines, including Azure Bastion and just-in-time (JIT) - Configure network isolation for Azure Kubernetes Service (AKS) - Secure and monitor AKS - Configure authentication for AKS - Configure security monitoring for Azure Container Instances (ACIs) - Configure security monitoring for Azure Container Apps (ACAs) - Manage access to Azure Container Registry (ACR) - Configure disk encryption, including Azure Disk Encryption (ADE), encryption at host, and confidential disk encryption - Recommend security configurations for Azure API Management #### 3.2 Plan and Implement Security for Storage - Configure access control for storage accounts - Manage storage account access keys - Select and configure an appropriate method for access to Azure Files - Select and configure an appropriate method for access to Azure Blob Storage - Select and configure appropriate methods for protecting against data security threats, including: - Soft delete - Backups - Versioning - Immutable storage - Configure Bring your own key (BYOK) - Enable double encryption at the Azure Storage infrastructure level #### 3.3 Plan and Implement Security for Azure SQL Database and Azure SQL Managed Instance - Enable Microsoft Entra database authentication - Enable database auditing - Plan and implement dynamic masking - Implement Transparent Data Encryption (TDE) - Recommend when to use Azure SQL Database Always Encrypted --- ### 4. Secure Azure using Microsoft Defender for Cloud and Microsoft Sentinel (30–35%) #### 4.1 Implement and Manage Enforcement of Cloud Governance Policies - Create, assign, and interpret policies and initiatives in Azure Policy - Configure Azure Key Vault network settings - Configure access to Key Vault, including vault access policies and Azure Role Based Access Control - Manage certificates, secrets, and keys - Configure key rotation - Perform backup and recovery of certificates, secrets, and keys - Implement security controls to protect backups - Implement security controls for asset management #### 4.2 Manage Security Posture by Using Microsoft Defender for Cloud - Identify and remediate security risks by using the Microsoft Defender for Cloud Secure Score and Inventory - Assess compliance against security frameworks by using Microsoft Defender for Cloud - Manage compliance standards in Microsoft Defender for Cloud - Add custom standards to Microsoft Defender for Cloud - Connect hybrid cloud and multi-cloud environments to Microsoft Defender for Cloud, including: - Amazon Web Services (AWS) - Google Cloud Platform (GCP) - Implement and use Microsoft Defender External Attack Surface Management (EASM) #### 4.3 Configure and Manage Threat Protection by Using Microsoft Defender for Cloud - Enable workload protection services in Microsoft Defender for Cloud - Configure Microsoft Defender for: - Servers - Databases - Storage - Implement and manage agentless scanning for virtual machines in Microsoft Defender for Servers - Implement and manage Microsoft Defender Vulnerability Management for Azure virtual machines - Connect to and configure settings in Microsoft Defender for Cloud Devops Security, including: - GitHub - Azure DevOps - GitLab #### 4.4 Configure and Manage Security Monitoring and Automation Solutions - Manage and respond to security alerts in Microsoft Defender for Cloud - Configure workflow automation by using Microsoft Defender for Cloud - Monitor network security events and performance data by configuring data collection rules (DCRs) in Azure Monitor - Configure data connectors in Microsoft Sentinel - Enable analytics rules in Microsoft Sentinel - Configure automation in Microsoft Sentinel ================================================ FILE: azure-cli.azcli ================================================ #!/bin/bash # AZ-500 Security Implementation Example # Purpose: Demonstrates security hardening and auditing across multiple Azure services # Set variables RG_NAME="SecurityAuditRG" LOCATION="eastus" STORAGE_ACCOUNT="securityauditsa$RANDOM" KEYVAULT_NAME="security-kv-$RANDOM" NSG_NAME="security-nsg" VNET_NAME="security-vnet" LOG_ANALYTICS_WORKSPACE="security-law" # Create Resource Group with tags for compliance az group create \ --name $RG_NAME \ --location $LOCATION \ --tags "Environment=Production" "DataClassification=Confidential" "ComplianceRequired=HIPAA" # Create VNet with custom subnet configuration az network vnet create \ --resource-group $RG_NAME \ --name $VNET_NAME \ --address-prefix 10.0.0.0/16 \ --subnet-name ApplicationSubnet \ --subnet-prefix 10.0.1.0/24 # Create NSG with security rules az network nsg create \ --resource-group $RG_NAME \ --name $NSG_NAME # Add security rules to NSG az network nsg rule create \ --resource-group $RG_NAME \ --nsg-name $NSG_NAME \ --name "DenyAllInbound" \ --priority 4096 \ --direction Inbound \ --access Deny \ --protocol "*" \ --source-address-prefixes "*" \ --source-port-ranges "*" \ --destination-address-prefixes "*" \ --destination-port-ranges "*" # Create Storage Account with security features az storage account create \ --name $STORAGE_ACCOUNT \ --resource-group $RG_NAME \ --location $LOCATION \ --sku Standard_GRS \ --kind StorageV2 \ --https-only true \ --min-tls-version TLS1_2 \ --allow-blob-public-access false \ --enable-hierarchical-namespace true # Enable Azure Defender for Storage az security pricing create \ --name "StorageAccounts" \ --tier "Standard" # Create Key Vault with advanced security features az keyvault create \ --name $KEYVAULT_NAME \ --resource-group $RG_NAME \ --location $LOCATION \ --sku Premium \ --enable-rbac-authorization true \ --enable-purge-protection true \ --retention-days 90 # Enable Key Vault logging az monitor diagnostic-settings create \ --name "KeyVaultAudit" \ --resource $KEYVAULT_NAME \ --resource-group $RG_NAME \ --resource-type "Microsoft.KeyVault/vaults" \ --logs '[{"category": "AuditEvent","enabled": true}]' \ --metrics '[{"category": "AllMetrics","enabled": true}]' # Create Log Analytics Workspace for security monitoring az monitor log-analytics workspace create \ --resource-group $RG_NAME \ --workspace-name $LOG_ANALYTICS_WORKSPACE \ --location $LOCATION \ --sku PerGB2018 # Enable Microsoft Defender for Cloud az security pricing create \ --name "VirtualMachines" \ --tier "Standard" # Configure security policies az security policy assignment create \ --name "SecurityBaselinePolicy" \ --display-name "Security Baseline" \ --policy-definition-id "/providers/Microsoft.Authorization/policyDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8" # Enable JIT VM Access az vm jit-policy create \ --resource-group $RG_NAME \ --location $LOCATION \ --vm-name "sample-vm" \ --jit-policy "{'jitNetworkAccessPolicy':{'virtualMachines':[{'id':'/subscriptions/{subscription-id}/resourceGroups/$RG_NAME/providers/Microsoft.Compute/virtualMachines/sample-vm','ports':[{'number':22,'protocol':'*','allowedSourceAddressPrefix':'*','maxRequestAccessDuration':'PT3H'}]}]}}" # Enable diagnostic settings for Activity Log az monitor diagnostic-settings create \ --name "SecurityAudit" \ --resource-group $RG_NAME \ --logs '[{"category": "Administrative","enabled": true},{"category": "Security","enabled": true}]' \ --workspace $LOG_ANALYTICS_WORKSPACE # Export security recommendations az security assessment list \ --resource-group $RG_NAME \ --query "[].{Name:name, Status:status.code, Description:metadata.description}" \ --output table # Configure custom security alerts az monitor activity-log alert create \ --name "SecurityAlert" \ --resource-group $RG_NAME \ --condition category="Security" \ --action-group "/subscriptions/{subscription-id}/resourceGroups/$RG_NAME/providers/microsoft.insights/actionGroups/SecurityTeam" echo "Security configuration completed. Review the Microsoft Defender for Cloud dashboard for security recommendations." ================================================ FILE: azure-policy.json ================================================ { "mode": "Indexed", "policyRule": { "if": { "allOf": [ { "field": "type", "equals": "Microsoft.Web/sites" } ] }, "then": { "effect": "deployIfNotExists", "details": { "type": "Microsoft.Web/sites", "name": "[field('name')]", "roleDefinitionIds": [ "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c" // Contributor role ], "existenceCondition": { "allOf": [ { "field": "identity.type", "contains": "UserAssigned" }, { "field": "identity.userAssignedIdentities", "exists": "true" } ] }, "deployment": { "properties": { "mode": "Incremental", "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "webAppName": { "type": "string" }, "location": { "type": "string" }, "userAssignedIdentityName": { "type": "string", "defaultValue": "[concat(parameters('webAppName'), '-identity')]" } }, "resources": [ { "type": "Microsoft.ManagedIdentity/userAssignedIdentities", "apiVersion": "2018-11-30", "name": "[parameters('userAssignedIdentityName')]", "location": "[parameters('location')]" }, { "type": "Microsoft.Web/sites", "apiVersion": "2022-03-01", "name": "[parameters('webAppName')]", "location": "[parameters('location')]", "identity": { "type": "UserAssigned", "userAssignedIdentities": { "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('userAssignedIdentityName'))]": {} } }, "dependsOn": [ "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('userAssignedIdentityName'))]" ] } ] }, "parameters": { "webAppName": { "value": "[field('name')]" }, "location": { "value": "[field('location')]" } } } } } } }, "parameters": {} } ================================================ FILE: azure-powershell.ps1 ================================================ ================================================ FILE: code-samples/README.md ================================================ # AZ-500 Code Samples This directory contains code samples, templates, and scripts that demonstrate Azure security concepts relevant to the AZ-500 exam. ## Directory Structure - **bicep/** - Azure Bicep templates for infrastructure-as-code deployments - **json/** - Azure Resource Manager (ARM) templates and JSON configuration files - **powershell/** - PowerShell scripts for Azure security automation - **cli/** - Azure CLI scripts for security configurations - **kusto/** - Kusto Query Language (KQL) samples for Azure Monitor and Sentinel ## How to Use These Samples These code samples are designed to help you understand and practice implementing Azure security concepts. Follow these steps: 1. **Review the code** to understand the security configurations 2. **Test in a sandbox environment** before applying to production 3. **Modify parameters** to match your specific requirements 4. **Reference the [Azure documentation](https://learn.microsoft.com/en-us/azure)** for detailed explanations ## Security Best Practices When using these code samples, remember to follow security best practices: - Use managed identities where possible - Apply the principle of least privilege for access control - Encrypt sensitive data at rest and in transit - Implement defense in depth with multiple security layers - Enable logging and monitoring for security-relevant events ## Contributing If you have improvements or additional samples, please follow the contribution guidelines in the main repository. ================================================ FILE: code-samples/bicep/deployment.bicep ================================================ // AZ-500 Security Implementation Example // Purpose: Demonstrates secure infrastructure deployment with multiple security controls // Parameters @description('Primary location for all resources') param location string = resourceGroup().location @description('Environment name') @allowed([ 'Production' 'Development' 'Test' ]) param environmentName string @description('IP addresses or ranges that should be allowed through the firewall') param allowedIPRanges array @description('Key Vault SKU') @allowed([ 'standard' 'premium' ]) param keyVaultSku string = 'premium' @minLength(3) @maxLength(24) @description('Storage Account name') param storageAccountName string @secure() @description('SQL Server administrator password') param sqlServerAdminPassword string // Variables var networkSecurityGroupName = 'security-nsg' var virtualNetworkName = 'security-vnet' var keyVaultName = 'kv-${uniqueString(resourceGroup().id)}' var logAnalyticsWorkspaceName = 'law-${uniqueString(resourceGroup().id)}' var applicationInsightsName = 'ai-${uniqueString(resourceGroup().id)}' // Tags var commonTags = { Environment: environmentName SecurityContact: 'security@contoso.com' DataClassification: 'Confidential' ComplianceRequired: 'HIPAA' } // Network Security Group resource nsg 'Microsoft.Network/networkSecurityGroups@2023-05-01' = { name: networkSecurityGroupName location: location tags: commonTags properties: { securityRules: [ { name: 'DenyAllInbound' properties: { priority: 4096 direction: 'Inbound' access: 'Deny' protocol: '*' sourceAddressPrefix: '*' sourcePortRange: '*' destinationAddressPrefix: '*' destinationPortRange: '*' } } ] } } // Virtual Network with Subnets resource vnet 'Microsoft.Network/virtualNetworks@2023-05-01' = { name: virtualNetworkName location: location tags: commonTags properties: { addressSpace: { addressPrefixes: [ '10.0.0.0/16' ] } subnets: [ { name: 'ApplicationSubnet' properties: { addressPrefix: '10.0.1.0/24' networkSecurityGroup: { id: nsg.id } serviceEndpoints: [ { service: 'Microsoft.KeyVault' } { service: 'Microsoft.Storage' } { service: 'Microsoft.Sql' } ] } } { name: 'DatabaseSubnet' properties: { addressPrefix: '10.0.2.0/24' delegations: [ { name: 'sqlDelegation' properties: { serviceName: 'Microsoft.Sql/managedInstances' } } ] } } ] } } // Key Vault with RBAC and Advanced Security resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { name: keyVaultName location: location tags: commonTags properties: { tenantId: subscription().tenantId sku: { family: 'A' name: keyVaultSku } enableRbacAuthorization: true enablePurgeProtection: true enabledForTemplateDeployment: true enabledForDiskEncryption: true networkAcls: { defaultAction: 'Deny' bypass: 'AzureServices' ipRules: [for ip in allowedIPRanges: { value: ip }] virtualNetworkRules: [ { id: '${vnet.id}/subnets/ApplicationSubnet' } ] } } } // Storage Account with Security Features resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { name: storageAccountName location: location tags: commonTags sku: { name: 'Standard_GRS' } kind: 'StorageV2' properties: { minimumTlsVersion: 'TLS1_2' supportsHttpsTrafficOnly: true encryption: { services: { blob: { enabled: true } file: { enabled: true } } keySource: 'Microsoft.Storage' } networkAcls: { defaultAction: 'Deny' bypass: 'AzureServices' virtualNetworkRules: [ { id: '${vnet.id}/subnets/ApplicationSubnet' action: 'Allow' } ] ipRules: [for ip in allowedIPRanges: { value: ip action: 'Allow' }] } } } // Log Analytics Workspace resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { name: logAnalyticsWorkspaceName location: location tags: commonTags properties: { sku: { name: 'PerGB2018' } retentionInDays: 90 features: { enableLogAccessUsingOnlyResourcePermissions: true } } } // Application Insights for Security Monitoring resource appInsights 'Microsoft.Insights/components@2020-02-02' = { name: applicationInsightsName location: location tags: commonTags kind: 'web' properties: { Application_Type: 'web' WorkspaceResourceId: logAnalytics.id DisableIpMasking: false DisableLocalAuth: true } } // Diagnostic Settings for Key Vault resource keyVaultDiagnostics 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = { scope: keyVault name: 'KeyVaultAudit' properties: { workspaceId: logAnalytics.id logs: [ { category: 'AuditEvent' enabled: true retentionPolicy: { enabled: true days: 90 } } ] metrics: [ { category: 'AllMetrics' enabled: true retentionPolicy: { enabled: true days: 90 } } ] } } // Role Assignments resource keyVaultAdminRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid(keyVault.id, 'Key Vault Administrator') scope: keyVault properties: { roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483') principalType: 'ServicePrincipal' principalId: 'YOUR-MANAGED-IDENTITY-ID' } } // Outputs output keyVaultName string = keyVault.name output storageAccountName string = storageAccount.name output vnetName string = vnet.name output logAnalyticsWorkspaceId string = logAnalytics.id ================================================ FILE: code-samples/cli/azure-cli.azcli ================================================ #!/bin/bash # AZ-500 Security Implementation Example # Purpose: Demonstrates security hardening and auditing across multiple Azure services # Set variables RG_NAME="SecurityAuditRG" LOCATION="eastus" STORAGE_ACCOUNT="securityauditsa$RANDOM" KEYVAULT_NAME="security-kv-$RANDOM" NSG_NAME="security-nsg" VNET_NAME="security-vnet" LOG_ANALYTICS_WORKSPACE="security-law" # Create Resource Group with tags for compliance az group create \ --name $RG_NAME \ --location $LOCATION \ --tags "Environment=Production" "DataClassification=Confidential" "ComplianceRequired=HIPAA" # Create VNet with custom subnet configuration az network vnet create \ --resource-group $RG_NAME \ --name $VNET_NAME \ --address-prefix 10.0.0.0/16 \ --subnet-name ApplicationSubnet \ --subnet-prefix 10.0.1.0/24 # Create NSG with security rules az network nsg create \ --resource-group $RG_NAME \ --name $NSG_NAME # Add security rules to NSG az network nsg rule create \ --resource-group $RG_NAME \ --nsg-name $NSG_NAME \ --name "DenyAllInbound" \ --priority 4096 \ --direction Inbound \ --access Deny \ --protocol "*" \ --source-address-prefixes "*" \ --source-port-ranges "*" \ --destination-address-prefixes "*" \ --destination-port-ranges "*" # Create Storage Account with security features az storage account create \ --name $STORAGE_ACCOUNT \ --resource-group $RG_NAME \ --location $LOCATION \ --sku Standard_GRS \ --kind StorageV2 \ --https-only true \ --min-tls-version TLS1_2 \ --allow-blob-public-access false \ --enable-hierarchical-namespace true # Enable Azure Defender for Storage az security pricing create \ --name "StorageAccounts" \ --tier "Standard" # Create Key Vault with advanced security features az keyvault create \ --name $KEYVAULT_NAME \ --resource-group $RG_NAME \ --location $LOCATION \ --sku Premium \ --enable-rbac-authorization true \ --enable-purge-protection true \ --retention-days 90 # Enable Key Vault logging az monitor diagnostic-settings create \ --name "KeyVaultAudit" \ --resource $KEYVAULT_NAME \ --resource-group $RG_NAME \ --resource-type "Microsoft.KeyVault/vaults" \ --logs '[{"category": "AuditEvent","enabled": true}]' \ --metrics '[{"category": "AllMetrics","enabled": true}]' # Create Log Analytics Workspace for security monitoring az monitor log-analytics workspace create \ --resource-group $RG_NAME \ --workspace-name $LOG_ANALYTICS_WORKSPACE \ --location $LOCATION \ --sku PerGB2018 # Enable Microsoft Defender for Cloud az security pricing create \ --name "VirtualMachines" \ --tier "Standard" # Configure security policies az security policy assignment create \ --name "SecurityBaselinePolicy" \ --display-name "Security Baseline" \ --policy-definition-id "/providers/Microsoft.Authorization/policyDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8" # Enable JIT VM Access az vm jit-policy create \ --resource-group $RG_NAME \ --location $LOCATION \ --vm-name "sample-vm" \ --jit-policy "{'jitNetworkAccessPolicy':{'virtualMachines':[{'id':'/subscriptions/{subscription-id}/resourceGroups/$RG_NAME/providers/Microsoft.Compute/virtualMachines/sample-vm','ports':[{'number':22,'protocol':'*','allowedSourceAddressPrefix':'*','maxRequestAccessDuration':'PT3H'}]}]}}" # Enable diagnostic settings for Activity Log az monitor diagnostic-settings create \ --name "SecurityAudit" \ --resource-group $RG_NAME \ --logs '[{"category": "Administrative","enabled": true},{"category": "Security","enabled": true}]' \ --workspace $LOG_ANALYTICS_WORKSPACE # Export security recommendations az security assessment list \ --resource-group $RG_NAME \ --query "[].{Name:name, Status:status.code, Description:metadata.description}" \ --output table # Configure custom security alerts az monitor activity-log alert create \ --name "SecurityAlert" \ --resource-group $RG_NAME \ --condition category="Security" \ --action-group "/subscriptions/{subscription-id}/resourceGroups/$RG_NAME/providers/microsoft.insights/actionGroups/SecurityTeam" echo "Security configuration completed. Review the Microsoft Defender for Cloud dashboard for security recommendations." ================================================ FILE: code-samples/json/azure-policy.json ================================================ { "mode": "Indexed", "policyRule": { "if": { "allOf": [ { "field": "type", "equals": "Microsoft.Web/sites" } ] }, "then": { "effect": "deployIfNotExists", "details": { "type": "Microsoft.Web/sites", "name": "[field('name')]", "roleDefinitionIds": [ "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c" // Contributor role ], "existenceCondition": { "allOf": [ { "field": "identity.type", "contains": "UserAssigned" }, { "field": "identity.userAssignedIdentities", "exists": "true" } ] }, "deployment": { "properties": { "mode": "Incremental", "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "webAppName": { "type": "string" }, "location": { "type": "string" }, "userAssignedIdentityName": { "type": "string", "defaultValue": "[concat(parameters('webAppName'), '-identity')]" } }, "resources": [ { "type": "Microsoft.ManagedIdentity/userAssignedIdentities", "apiVersion": "2018-11-30", "name": "[parameters('userAssignedIdentityName')]", "location": "[parameters('location')]" }, { "type": "Microsoft.Web/sites", "apiVersion": "2022-03-01", "name": "[parameters('webAppName')]", "location": "[parameters('location')]", "identity": { "type": "UserAssigned", "userAssignedIdentities": { "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('userAssignedIdentityName'))]": {} } }, "dependsOn": [ "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('userAssignedIdentityName'))]" ] } ] }, "parameters": { "webAppName": { "value": "[field('name')]" }, "location": { "value": "[field('location')]" } } } } } } }, "parameters": {} } ================================================ FILE: code-samples/json/custom-rbac-role.json ================================================ { "Name": "Security Operations Analyst Custom Role", "IsCustom": true, "Description": "Allows security operations team to monitor security-related resources, manage security alerts, and perform specific remediation actions while maintaining separation of duties.", "Actions": [ "Microsoft.Security/alerts/read", "Microsoft.Security/securitySolutions/read", "Microsoft.Security/policies/read", "Microsoft.Security/pricings/read", "Microsoft.Security/settings/read", "Microsoft.Security/assessments/read", "Microsoft.Network/networkWatchers/read", "Microsoft.Network/networkSecurityGroups/read", "Microsoft.KeyVault/vaults/read", "Microsoft.Insights/alertRules/*", "Microsoft.Resources/subscriptions/resourceGroups/read" ], "NotActions": [ "Microsoft.KeyVault/vaults/delete", "Microsoft.KeyVault/vaults/write", "Microsoft.Network/networkSecurityGroups/write", "Microsoft.Network/networkSecurityGroups/delete" ], "DataActions": [ "Microsoft.KeyVault/vaults/secrets/read", "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read", "Microsoft.Insights/Logs/Read" ], "NotDataActions": [ "Microsoft.KeyVault/vaults/secrets/write", "Microsoft.KeyVault/vaults/secrets/delete", "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write", "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/delete" ], "AssignableScopes": [ "/subscriptions/00000000-0000-0000-0000-000000000000", "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/SecurityOperations", "/providers/Microsoft.Management/managementGroups/SecurityTeam" ] } ================================================ FILE: code-samples/json/deployment.json ================================================ ================================================ FILE: code-samples/kusto/kusto.kql ================================================ // Security Investigation Query - Correlated Security Events Analysis // Purpose: Detect potential lateral movement attempts by correlating failed login attempts // with subsequent successful logins and suspicious process executions // First, let's get failed login attempts let FailedLogins = SecurityEvent | where TimeGenerated > ago(24h) | where EventID == 4625 // Failed login attempt | where AccountType == "User" | project TimeGenerated, SourceComputer = Computer, TargetAccount = tolower(TargetUserName), SourceIP = IpAddress, FailureReason = Status; // Get successful logins that happened after failed attempts let SuccessfulLogins = SecurityEvent | where TimeGenerated > ago(24h) | where EventID == 4624 // Successful login | where LogonType in (3, 10) // Network and RemoteInteractive logons | project LoginTime = TimeGenerated, DestinationHost = Computer, TargetAccount = tolower(TargetUserName), LogonType, SourceIP = IpAddress; // Get suspicious process executions let SuspiciousProcesses = SecurityEvent | where TimeGenerated > ago(24h) | where EventID == 4688 // Process creation | where CommandLine has_any("mimikatz", "psexec", "wmic", "powershell -enc") | project ProcessTime = TimeGenerated, Host = Computer, Account = tolower(SubjectUserName), ProcessName = Process, CommandLine; // Correlate all events FailedLogins | join kind=inner ( SuccessfulLogins | where LoginTime > TimeGenerated // Only get logins that happened after failed attempts ) on TargetAccount | where LoginTime - TimeGenerated < timespan(1h) // Within 1 hour | join kind=leftouter ( SuspiciousProcesses | where ProcessTime > TimeGenerated // Only get processes that ran after failed attempts ) on $left.TargetAccount == $right.Account | where ProcessTime - LoginTime < timespan(2h) or isnull(ProcessTime) // Within 2 hours of successful login | project InitialFailureTime = TimeGenerated, SuccessfulLoginTime = LoginTime, SuspiciousProcessTime = ProcessTime, TargetAccount, SourceIP, DestinationHost, FailureReason, LogonType, SuspiciousProcess = ProcessName, SuspiciousCommandLine = CommandLine | sort by InitialFailureTime asc | extend TimeBetweenFailureAndSuccess = datetime_diff('minute', SuccessfulLoginTime, InitialFailureTime) | extend AlertSeverity = case( isnotnull(SuspiciousProcess), "High", TimeBetweenFailureAndSuccess < 10, "Medium", "Low" ) | summarize FailedLoginCount = count(), UniqueSourceIPs = dcount(SourceIP), AffectedHosts = make_set(DestinationHost), SuspiciousProcesses = make_set(SuspiciousProcess) by TargetAccount, AlertSeverity | extend RecommendedAction = case( AlertSeverity == "High", "Immediate investigation required. Consider account suspension.", AlertSeverity == "Medium", "Review login patterns and validate with user.", "Monitor for additional suspicious activity." ) ================================================ FILE: code-samples/powershell/azure-powershell.ps1 ================================================ ================================================ FILE: custom-rbac-role.json ================================================ { "Name": "Security Operations Analyst Custom Role", "IsCustom": true, "Description": "Allows security operations team to monitor security-related resources, manage security alerts, and perform specific remediation actions while maintaining separation of duties.", "Actions": [ "Microsoft.Security/alerts/read", "Microsoft.Security/securitySolutions/read", "Microsoft.Security/policies/read", "Microsoft.Security/pricings/read", "Microsoft.Security/settings/read", "Microsoft.Security/assessments/read", "Microsoft.Network/networkWatchers/read", "Microsoft.Network/networkSecurityGroups/read", "Microsoft.KeyVault/vaults/read", "Microsoft.Insights/alertRules/*", "Microsoft.Resources/subscriptions/resourceGroups/read" ], "NotActions": [ "Microsoft.KeyVault/vaults/delete", "Microsoft.KeyVault/vaults/write", "Microsoft.Network/networkSecurityGroups/write", "Microsoft.Network/networkSecurityGroups/delete" ], "DataActions": [ "Microsoft.KeyVault/vaults/secrets/read", "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read", "Microsoft.Insights/Logs/Read" ], "NotDataActions": [ "Microsoft.KeyVault/vaults/secrets/write", "Microsoft.KeyVault/vaults/secrets/delete", "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write", "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/delete" ], "AssignableScopes": [ "/subscriptions/00000000-0000-0000-0000-000000000000", "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/SecurityOperations", "/providers/Microsoft.Management/managementGroups/SecurityTeam" ] } ================================================ FILE: deployment.bicep ================================================ // AZ-500 Security Implementation Example // Purpose: Demonstrates secure infrastructure deployment with multiple security controls // Parameters @description('Primary location for all resources') param location string = resourceGroup().location @description('Environment name') @allowed([ 'Production' 'Development' 'Test' ]) param environmentName string @description('IP addresses or ranges that should be allowed through the firewall') param allowedIPRanges array @description('Key Vault SKU') @allowed([ 'standard' 'premium' ]) param keyVaultSku string = 'premium' @minLength(3) @maxLength(24) @description('Storage Account name') param storageAccountName string @secure() @description('SQL Server administrator password') param sqlServerAdminPassword string // Variables var networkSecurityGroupName = 'security-nsg' var virtualNetworkName = 'security-vnet' var keyVaultName = 'kv-${uniqueString(resourceGroup().id)}' var logAnalyticsWorkspaceName = 'law-${uniqueString(resourceGroup().id)}' var applicationInsightsName = 'ai-${uniqueString(resourceGroup().id)}' // Tags var commonTags = { Environment: environmentName SecurityContact: 'security@contoso.com' DataClassification: 'Confidential' ComplianceRequired: 'HIPAA' } // Network Security Group resource nsg 'Microsoft.Network/networkSecurityGroups@2023-05-01' = { name: networkSecurityGroupName location: location tags: commonTags properties: { securityRules: [ { name: 'DenyAllInbound' properties: { priority: 4096 direction: 'Inbound' access: 'Deny' protocol: '*' sourceAddressPrefix: '*' sourcePortRange: '*' destinationAddressPrefix: '*' destinationPortRange: '*' } } ] } } // Virtual Network with Subnets resource vnet 'Microsoft.Network/virtualNetworks@2023-05-01' = { name: virtualNetworkName location: location tags: commonTags properties: { addressSpace: { addressPrefixes: [ '10.0.0.0/16' ] } subnets: [ { name: 'ApplicationSubnet' properties: { addressPrefix: '10.0.1.0/24' networkSecurityGroup: { id: nsg.id } serviceEndpoints: [ { service: 'Microsoft.KeyVault' } { service: 'Microsoft.Storage' } { service: 'Microsoft.Sql' } ] } } { name: 'DatabaseSubnet' properties: { addressPrefix: '10.0.2.0/24' delegations: [ { name: 'sqlDelegation' properties: { serviceName: 'Microsoft.Sql/managedInstances' } } ] } } ] } } // Key Vault with RBAC and Advanced Security resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { name: keyVaultName location: location tags: commonTags properties: { tenantId: subscription().tenantId sku: { family: 'A' name: keyVaultSku } enableRbacAuthorization: true enablePurgeProtection: true enabledForTemplateDeployment: true enabledForDiskEncryption: true networkAcls: { defaultAction: 'Deny' bypass: 'AzureServices' ipRules: [for ip in allowedIPRanges: { value: ip }] virtualNetworkRules: [ { id: '${vnet.id}/subnets/ApplicationSubnet' } ] } } } // Storage Account with Security Features resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { name: storageAccountName location: location tags: commonTags sku: { name: 'Standard_GRS' } kind: 'StorageV2' properties: { minimumTlsVersion: 'TLS1_2' supportsHttpsTrafficOnly: true encryption: { services: { blob: { enabled: true } file: { enabled: true } } keySource: 'Microsoft.Storage' } networkAcls: { defaultAction: 'Deny' bypass: 'AzureServices' virtualNetworkRules: [ { id: '${vnet.id}/subnets/ApplicationSubnet' action: 'Allow' } ] ipRules: [for ip in allowedIPRanges: { value: ip action: 'Allow' }] } } } // Log Analytics Workspace resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { name: logAnalyticsWorkspaceName location: location tags: commonTags properties: { sku: { name: 'PerGB2018' } retentionInDays: 90 features: { enableLogAccessUsingOnlyResourcePermissions: true } } } // Application Insights for Security Monitoring resource appInsights 'Microsoft.Insights/components@2020-02-02' = { name: applicationInsightsName location: location tags: commonTags kind: 'web' properties: { Application_Type: 'web' WorkspaceResourceId: logAnalytics.id DisableIpMasking: false DisableLocalAuth: true } } // Diagnostic Settings for Key Vault resource keyVaultDiagnostics 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = { scope: keyVault name: 'KeyVaultAudit' properties: { workspaceId: logAnalytics.id logs: [ { category: 'AuditEvent' enabled: true retentionPolicy: { enabled: true days: 90 } } ] metrics: [ { category: 'AllMetrics' enabled: true retentionPolicy: { enabled: true days: 90 } } ] } } // Role Assignments resource keyVaultAdminRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid(keyVault.id, 'Key Vault Administrator') scope: keyVault properties: { roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483') principalType: 'ServicePrincipal' principalId: 'YOUR-MANAGED-IDENTITY-ID' } } // Outputs output keyVaultName string = keyVault.name output storageAccountName string = storageAccount.name output vnetName string = vnet.name output logAnalyticsWorkspaceId string = logAnalytics.id ================================================ FILE: deployment.json ================================================ ================================================ FILE: docs/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project maintainer using any of the [private contact addresses](https://github.com/timothywarner/az500#support). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.4, available at For answers to common questions about this code of conduct, see ================================================ FILE: docs/CONTRIBUTING.md ================================================ # Contributing When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change. Please note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in all your interactions with the project. ## Development environment setup > **[?]** > Proceed to describe how to setup local development environment. > e.g: To set up a development environment, please follow these steps: 1. Clone the repo ```sh git clone https://github.com/timothywarner/az500 ``` 2. TODO ## Issues and feature requests You've found a bug in the source code, a mistake in the documentation or maybe you'd like a new feature? You can help us by submitting an issue to our [GitHub Repository](https://github.com/timothywarner/az500/issues). Before you create an issue, make sure you search the archive, maybe your question was already answered. Please try to create bug reports that are: - _Reproducible._ Include steps to reproduce the problem. - _Specific._ Include as much detail as possible: which version, what environment, etc. - _Unique._ Do not duplicate existing opened issues. - _Scoped to a Single Bug._ One bug per report. Even better: You could submit a pull request with a fix or new feature! ## Pull request process 1. Search our repository for open or closed [pull requests](https://github.com/timothywarner/az500/pulls) that relates to your submission. You don't want to duplicate effort. 2. Fork the project 3. Create your feature branch (`git checkout -b feat/amazing_feature`) 4. Commit your changes (`git commit -m 'feat: add amazing_feature'`) 5. Push to the branch (`git push origin feat/amazing_feature`) 6. Open a pull request Exam AZ-500: Microsoft Azure Security Technologies Crash Course uses [conventional commits](https://www.conventionalcommits.org), so please follow the specification. ================================================ FILE: docs/SECURITY.md ================================================ # Security Policy ## Reporting a Vulnerability If there are any vulnerability in **Exam AZ-500: Microsoft Azure Security Technologies Crash Course** project, don't hesitate to _report them_. 1. Use any of the [private contact addresses](https://github.com/timothywarner/az500#support). 2. Describe the vulnerability. - If you have a fix, explain or attach it. - In the near time, expect a reply with the required steps. Also, there may be a demand for a pull request which include the fixes. > You should not disclose the vulnerability publicly if you haven't received an answer in some weeks. > If the vulnerability is rejected, you may post it publicly within some hour of rejection, unless the rejection is withdrawn within that time period. > After the vulnerability has been fixed, you may disclose the vulnerability details publicly over some days. ================================================ FILE: kusto.kql ================================================ // Security Investigation Query - Correlated Security Events Analysis // Purpose: Detect potential lateral movement attempts by correlating failed login attempts // with subsequent successful logins and suspicious process executions // First, let's get failed login attempts let FailedLogins = SecurityEvent | where TimeGenerated > ago(24h) | where EventID == 4625 // Failed login attempt | where AccountType == "User" | project TimeGenerated, SourceComputer = Computer, TargetAccount = tolower(TargetUserName), SourceIP = IpAddress, FailureReason = Status; // Get successful logins that happened after failed attempts let SuccessfulLogins = SecurityEvent | where TimeGenerated > ago(24h) | where EventID == 4624 // Successful login | where LogonType in (3, 10) // Network and RemoteInteractive logons | project LoginTime = TimeGenerated, DestinationHost = Computer, TargetAccount = tolower(TargetUserName), LogonType, SourceIP = IpAddress; // Get suspicious process executions let SuspiciousProcesses = SecurityEvent | where TimeGenerated > ago(24h) | where EventID == 4688 // Process creation | where CommandLine has_any("mimikatz", "psexec", "wmic", "powershell -enc") | project ProcessTime = TimeGenerated, Host = Computer, Account = tolower(SubjectUserName), ProcessName = Process, CommandLine; // Correlate all events FailedLogins | join kind=inner ( SuccessfulLogins | where LoginTime > TimeGenerated // Only get logins that happened after failed attempts ) on TargetAccount | where LoginTime - TimeGenerated < timespan(1h) // Within 1 hour | join kind=leftouter ( SuspiciousProcesses | where ProcessTime > TimeGenerated // Only get processes that ran after failed attempts ) on $left.TargetAccount == $right.Account | where ProcessTime - LoginTime < timespan(2h) or isnull(ProcessTime) // Within 2 hours of successful login | project InitialFailureTime = TimeGenerated, SuccessfulLoginTime = LoginTime, SuspiciousProcessTime = ProcessTime, TargetAccount, SourceIP, DestinationHost, FailureReason, LogonType, SuspiciousProcess = ProcessName, SuspiciousCommandLine = CommandLine | sort by InitialFailureTime asc | extend TimeBetweenFailureAndSuccess = datetime_diff('minute', SuccessfulLoginTime, InitialFailureTime) | extend AlertSeverity = case( isnotnull(SuspiciousProcess), "High", TimeBetweenFailureAndSuccess < 10, "Medium", "Low" ) | summarize FailedLoginCount = count(), UniqueSourceIPs = dcount(SourceIP), AffectedHosts = make_set(DestinationHost), SuspiciousProcesses = make_set(SuspiciousProcess) by TargetAccount, AlertSeverity | extend RecommendedAction = case( AlertSeverity == "High", "Immediate investigation required. Consider account suspension.", AlertSeverity == "Medium", "Review login patterns and validate with user.", "Monitor for additional suspicious activity." ) ================================================ FILE: labs/LAB-SETUP.md ================================================ # AZ-500 Lab Environment Setup Guide This guide will help you prepare your environment for the hands-on labs in this AZ-500 crash course. ## Prerequisites ### Azure Subscription You'll need an Azure subscription with: - Owner or Contributor rights - Sufficient quota for creating the following resources: - Virtual Networks - Virtual Machines (2-3 B-series VMs) - Storage Accounts - Key Vault - Microsoft Defender for Cloud (Standard tier features) ### Recommended Options: 1. **Azure Pass** (if provided by instructor) 2. **Free Azure Account** ([Create here](https://azure.microsoft.com/en-us/free/)) 3. **Visual Studio Subscription** (formerly MSDN) 4. **Company subscription** (if allowed for training) ### Local Environment Setup 1. **Required Software:** - [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) (latest version) - [PowerShell 7+](https://github.com/PowerShell/PowerShell#get-powershell) - [Az PowerShell module](https://docs.microsoft.com/en-us/powershell/azure/install-az-ps) - [Visual Studio Code](https://code.visualstudio.com/download) 2. **VS Code Extensions:** - [Azure Account](https://marketplace.visualstudio.com/items?itemName=ms-vscode.azure-account) - [Azure CLI Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.azure-cli) - [PowerShell](https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell) - [Azure Resource Manager Tools](https://marketplace.visualstudio.com/items?itemName=msazurermtools.azurerm-vscode-tools) ## Quick Setup Steps ### 1. Verify Azure CLI Installation ```bash # Check version az --version # Login to Azure az login # List subscriptions az account list --output table # Set your subscription (if you have multiple) az account set --subscription "Your-Subscription-Name-or-ID" ``` ### 2. Verify PowerShell Setup ```powershell # Check PowerShell version $PSVersionTable.PSVersion # Install/update Az module if needed Install-Module -Name Az -Force -AllowClobber -Scope CurrentUser # Login to Azure Connect-AzAccount # List subscriptions Get-AzSubscription # Set your subscription (if you have multiple) Set-AzContext -Subscription "Your-Subscription-Name-or-ID" ``` ### 3. Create Resource Group for Labs ```bash # Azure CLI az group create --name AZ500-Labs --location eastus2 # PowerShell New-AzResourceGroup -Name AZ500-Labs -Location eastus2 ``` ### 4. Enable Microsoft Defender for Cloud For some labs, we'll use Microsoft Defender for Cloud. Enable it in advance: 1. Navigate to **Microsoft Defender for Cloud** in the Azure Portal 2. Go to **Environment Settings** 3. Select your subscription 4. Enable the **Servers** and **Databases** plans (you can disable after the course) 5. Set **Continuous export** to **On** ### 5. Download Lab Files Clone this repository to have local access to all lab files: ```bash git clone https://github.com/timothywarner/az500 cd az500 ``` ## Troubleshooting Tips ### Cannot Create Resources / Permission Issues - Verify you have Owner or Contributor role on your subscription - Check if you have any Resource Policy restrictions - Ensure you're working in the correct subscription ### Azure CLI or PowerShell Connection Issues - Re-authenticate with `az login` or `Connect-AzAccount` - Check your internet connection - Verify any proxy or firewall settings ### Resource Creation Fails - Check your subscription quota limits - Try a different region if you're hitting regional limits - Ensure you've accepted any required marketplace terms ## Getting Help During Labs If you encounter issues during the labs: 1. Check the lab instructions carefully for any hints 2. Ask the instructor during the session 3. Search the [Microsoft Q&A for Azure](https://docs.microsoft.com/en-us/answers/products/azure?product=all) Good luck with your labs! ================================================ FILE: labs/README.md ================================================ # AZ-500 Hands-on Labs This directory contains hands-on labs and exercises to help you practice Azure security concepts relevant to the AZ-500 exam. ## Lab Environment Setup Before beginning the labs, ensure you have: 1. An **Azure subscription** with sufficient permissions 2. **Visual Studio Code** with Azure extensions installed 3. **Azure CLI** and **PowerShell** with Az modules 4. **Git** for downloading lab materials ## Lab Modules The labs are organized to align with the main exam skill areas: ### Module 1: Identity and Access Management - Configuring Microsoft Entra ID for workloads - Implementing Privileged Identity Management - Implementing RBAC and custom roles ### Module 2: Platform Protection - Implementing network security - Configuring advanced security for compute - Implementing container security ### Module 3: Security Operations - Configuring security policies - Working with Microsoft Defender for Cloud - Security monitoring with Azure Sentinel ### Module 4: Data and Application Security - Configuring security for storage - Configuring security for databases - Implementing Azure Key Vault ## Using the Official Microsoft Labs Microsoft provides an excellent set of official AZ-500 labs: 1. Visit the [Microsoft Learning AZ-500 GitHub Repository](https://microsoftlearning.github.io/AZ500-AzureSecurityTechnologies/) 2. Choose a lab module that matches your study area 3. Follow the step-by-step instructions 4. Review the concepts after completing each lab ## Lab Best Practices - **Clean up resources** after completing labs to avoid unnecessary charges - **Take notes** during labs to document key concepts and commands - **Experiment beyond** the instructions to deepen your understanding - **Create Azure free account** if you don't have a subscription Remember that hands-on experience is crucial for mastering the skills needed for the AZ-500 exam. Try to complete all labs to ensure comprehensive preparation. ================================================ FILE: scripts/blueprints/basic-networking-blueprint/Artifacts/7ddd6a5f-4815-4526-aa69-40bbffd263d3.json ================================================ { "kind": "roleAssignment", "properties": { "displayName": "Melissa Gaughan (melissa@timw.info) : Contributor", "dependsOn": [], "roleDefinitionId": "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c", "principalIds": [ "f798da5e-6a8b-4150-949f-c393dc8314bb" ], "resourceGroup": "SingleRG" } } ================================================ FILE: scripts/blueprints/basic-networking-blueprint/Artifacts/7ddd6a5f-4815-4526-aa69-40bbffd26cc7.json ================================================ { "kind": "policyAssignment", "properties": { "displayName": "Inherit a tag from the resource group if missing", "dependsOn": [], "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/ea3f2387-9b95-492a-a190-fcdc54f7b070", "parameters": { "tagName": { "value": "class" } }, "resourceGroup": "SingleRG" } } ================================================ FILE: scripts/blueprints/basic-networking-blueprint/Artifacts/nsg-template.json ================================================ { "kind": "template", "properties": { "displayName": "NSG for new VNET", "description": "", "dependsOn": [ "vnet-and-subnet-template" ], "template": { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "localPrefix": { "type": "string", "metadata": { "displayName": "Prefix for the resource names deployed in this template" } } }, "variables": { "subnetId": "[resourceId(resourceGroup().name, 'Microsoft.Network/virtualNetworks/subnets', concat(parameters('localPrefix'),'vnet-blueprint'), concat(parameters('localPrefix'),'subnet-blueprint'))]", "location": "[resourceGroup().location]", "existingVirtualNetworkResourceGroupName": "[resourceGroup().name]", "existingVirtualNetworkName": "[concat(parameters('localPrefix'), 'vnet-blueprint')]", "existingSubnetName": "[concat(parameters('localPrefix'), 'subnet-blueprint')]", "newNsgName": "[concat(parameters('localPrefix'), 'nsg-blueprint')]" }, "resources": [ { "type": "Microsoft.Network/networkSecurityGroups", "apiVersion": "2018-04-01", "name": "[variables('newNsgName')]", "location": "[variables('location')]", "properties": { "securityRules": [] } }, { "apiVersion": "2018-02-01", "type": "Microsoft.Resources/deployments", "name": "associateNsg", "resourceGroup": "[resourceGroup().name]", "dependsOn": [ "[variables('newNsgName')]" ], "properties": { "mode": "Incremental", "template": { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", "contentVersion": "1.0.0.0", "resources": [ { "apiVersion": "2018-04-01", "type": "Microsoft.Network/virtualNetworks/subnets", "name": "[concat(variables('existingVirtualNetworkName'), '/', variables('existingSubnetName'))]", "location": "[variables('location')]", "properties": { "addressPrefix": "[reference(variables('subnetId'), '2018-04-01').addressPrefix]", "networkSecurityGroup": { "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('newNsgName'))]" } } } ] } } } ] }, "resourceGroup": "SingleRG", "parameters": { "localPrefix": { "value": "[parameters('resourceNamePrefix')]" } } } } ================================================ FILE: scripts/blueprints/basic-networking-blueprint/Artifacts/vnet-and-subnet-template.json ================================================ { "kind": "template", "properties": { "displayName": "VNET and one subnet", "dependsOn": [], "template": { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "localPrefix": { "type": "string", "metadata": { "displayName": "Prefix for the resource names deployed in this template" } }, "addressSpaceVnet": { "type": "string", "defaultValue": "10.0.0.0/16" }, "addressSpaceSubnet": { "type": "string", "defaultValue": "10.0.0.0/24" } }, "resources": [ { "apiVersion": "2015-06-15", "type": "Microsoft.Network/virtualNetworks", "name": "[concat(parameters('localPrefix'), 'vnet-blueprint')]", "location": "[resourceGroup().location]", "properties": { "addressSpace": { "addressPrefixes": [ "[parameters('addressSpaceVnet')]" ] }, "subnets": [ { "name": "[concat(parameters('localPrefix'), 'subnet-blueprint')]", "properties": { "addressPrefix": "[parameters('addressSpaceSubnet')]" } } ] } } ] }, "resourceGroup": "SingleRG", "parameters": { "localPrefix": { "value": "[parameters('resourceNamePrefix')]" }, "addressSpaceVnet": { "value": "[parameters('addressSpaceForVnet')]" }, "addressSpaceSubnet": { "value": "[parameters('addressSpaceForSubnet')]" } } } } ================================================ FILE: scripts/blueprints/basic-networking-blueprint/Blueprint.json ================================================ { "properties": { "displayName": "Basic Networking (VNET)", "description": "Configures a virtual network with a subnet and an NSG.", "targetScope": "subscription", "parameters": { "resourceNamePrefix": { "type": "string", "metadata": { "displayName": "Resource name prefix", "description": "Resource group and resource name prefix" } }, "addressSpaceForVnet": { "type": "string", "metadata": { "displayName": "Addess space for vnet" }, "defaultValue": "10.0.0.0/16" }, "addressSpaceForSubnet": { "type": "string", "metadata": { "displayName": "Addess space for subnet" }, "defaultValue": "10.0.0.0/24" } }, "resourceGroups": { "SingleRG": { "location": "eastus", "metadata": { "displayName": "VNET Resource Group" }, "dependsOn": [], "tags": { "class": "user-group" } } }, "blueprintName": "basic-networking-blueprint" } } ================================================ FILE: scripts/blueprints/blueprints-references.txt ================================================ ##### Azure Blueprints Learning Resources ##### Azure Blueprints documentation https://docs.microsoft.com/en-us/azure/governance/blueprints/ Understand the lifecycle of a blueprint - Azure Blueprints | Microsoft Docs https://docs.microsoft.com/en-us/azure/governance/blueprints/concepts/lifecycle An overview of Azure Blueprints | Azure Friday - YouTube https://www.youtube.com/watch?v=cQ9D-d6KkMY Azure Governance - #3 - Policy & Blueprints - YouTube https://www.youtube.com/watch?v=EwO25vecGUo Sample Blueprint Definitions https://github.com/azure/azure-blueprints Azure Blueprint Tutorial https://agazoth.github.io/blogpost/2018/11/11/Azure-Blueprint.html Import/Export Azure Blueprints using Manage-AzureRMBlueprint PowerShell Script https://www.youtube.com/watch?v=SMORUIPhKd8&feature=youtu.be Azure Blueprints PowerShell https://github.com/JimGBritt/AzureBlueprint/ Azure Blueprint PowerShell, Part 2 https://github.com/Agazoth/AzureBlueprint Azure Blueprints via Azure DevOps Pipeline​ https://www.linkedin.com/pulse/azure-blueprints-via-devops-pipeline-paul-towler/ Azure Blueprints pipeline scripts https://github.com/Azure/azure-blueprints/tree/master/pipelines-scripts Azure Blueprints - Visual Studio Extension https://marketplace.visualstudio.com/items?itemName=nepeters.azure-blueprints ================================================ FILE: scripts/blueprints/blueprints.ps1 ================================================ <# Manage Azure Blueprints as code Tim Warner (techtrainertim.com) 01-September-2020 #> # Authenticate Connect-AzAccount Set-AzContext -SubscriptionName 'Microsoft Azure Sponsorship' # Install the Blueprints module Install-Module -Name Az.Blueprint -Verbose # Export an existing Azure blueprint to the local system $bp = Get-AzBlueprint -Name 'basic-networking-blueprint' Export-AzBlueprintWithArtifact -Blueprint $bp -OutputPath '.' -Version '1.0' # Push sample blueprint to Azure as a draft Import-AzBlueprintWithArtifact -Name Boilerplate -ManagementGroupId "DevMG" -InputPath ".\samples\101-boilerplate" # Publish a new version so it can be assigned: # Get the blueprint we just created $bp = Get-AzBlueprint -Name Boilerplate -ManagementGroupId "DevMG" # Publish version 1.0 Publish-AzBlueprint -Bluerpint $bp -Version 1.0 # Assign blueprint to a subscription # Get the version of the blueprint you want to assign, which we will pas to New-AzBlueprintAssignment $publishedBp = Get-AzBlueprint -ManagementGroupId "DevMG" -Name "Boilerplate" -LatestPublished # Each resource group artifact in the blueprint will need a hashtable for the actual RG name and location $rgHash = @{ name = "MyBoilerplateRG"; location = "eastus" } # all other (non-rg) parameters are listed in a single hashtable, with a key/value pair for each parameter $parameters = @{ principalIds = "caeebed6-cfa8-45ff-9d8a-03dba4ef9a7d" } # All of the resource group artifact hashtables are themselves grouped into a parent hashtable # the 'key' for each item in the table should match the RG placeholder name in the blueprint $rgArray = @{ SingleRG = $rgHash } # Assign the new blueprint to the specified subscription (Assignment updates should use Set-AzBlueprintAssignment New-AzBlueprintAssignment -Blueprint $publishedBp -Location eastus -SubscriptionId "00000000-1111-0000-1111-000000000000" -ResourceGroupParameter $rgArray -Parameter $parameters ================================================ FILE: scripts/blueprints/sample-blueprint/artifacts/policyStorageTags.json ================================================ { "kind": "policyAssignment", "properties": { "displayName": "Apply storage tag to resource group", "description": "Apply storage tag and the parameter also used by the template to resource groups", "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/49c88fc8-6fd1-46fd-a676-f12d1d3a4c71", "parameters": { "tagName": { "value": "StorageType" }, "tagValue": { "value": "[parameters('storageAccountType')]" } } } } ================================================ FILE: scripts/blueprints/sample-blueprint/artifacts/policyTags.json ================================================ { "kind": "policyAssignment", "properties": { "displayName": "Apply tag and its default value to resource groups", "description": "Apply tag and its default value to resource groups", "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/49c88fc8-6fd1-46fd-a676-f12d1d3a4c71", "parameters": { "tagName": { "value": "[parameters('tagName')]" }, "tagValue": { "value": "[parameters('tagValue')]" } } } } ================================================ FILE: scripts/blueprints/sample-blueprint/artifacts/roleContributor.json ================================================ { "kind": "roleAssignment", "properties": { "roleDefinitionId": "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c", "principalIds": "[parameters('contributors')]" } } ================================================ FILE: scripts/blueprints/sample-blueprint/artifacts/roleOwner.json ================================================ { "kind": "roleAssignment", "properties": { "resourceGroup": "storageRG", "roleDefinitionId": "/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635", "principalIds": "[parameters('owners')]" } } ================================================ FILE: scripts/blueprints/sample-blueprint/artifacts/templateStorage.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "storageAccountTypeFromBP": { "type": "string", "metadata": { "description": "Storage Account type" } }, "tagNameFromBP": { "type": "string", "defaultValue": "NotSet", "metadata": { "description": "Tag name from blueprint" } }, "tagValueFromBP": { "type": "string", "defaultValue": "NotSet", "metadata": { "description": "Tag value from blueprint" } } }, "variables": { "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'standardsa')]" }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "name": "[variables('storageAccountName')]", "apiVersion": "2016-01-01", "tags": { "[parameters('tagNameFromBP')]": "[parameters('tagValueFromBP')]" }, "location": "[resourceGroup().location]", "sku": { "name": "[parameters('storageAccountTypeFromBP')]" }, "kind": "Storage", "properties": {} } ], "outputs": { "storageAccountSku": { "type": "string", "value": "[variables('storageAccountName')]" } } } ================================================ FILE: scripts/blueprints/sample-blueprint/artifacts/templateStorageParams.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "storageAccountTypeFromBP": { "value": "[parameters('storageAccountType')]" }, "tagNameFromBP": { "value": "[parameters('tagName')]" }, "tagValueFromBP": { "value": "[parameters('tagValue')]" } } } ================================================ FILE: scripts/blueprints/sample-blueprint/blueprint.json ================================================ { "properties": { "description": "This blueprint sets tag policy and role assignment on the subscription, creates a ResourceGroup, and deploys a resource template and role assignment to that ResourceGroup.", "targetScope": "subscription", "parameters": { "storageAccountType": { "type": "string", "defaultValue": "Standard_LRS", "allowedValues": [ "Standard_LRS", "Standard_GRS", "Standard_ZRS", "Premium_LRS" ], "metadata": { "displayName": "storage account type.", "description": null } }, "tagName": { "type": "string", "metadata": { "displayName": "The name of the tag to provide the policy assignment.", "description": null } }, "tagValue": { "type": "string", "metadata": { "displayName": "The value of the tag to provide the policy assignment.", "description": null } }, "contributors": { "type": "array", "metadata": { "description": "List of AAD object IDs that is assigned Contributor role at the subscription", "strongType": "PrincipalId" } }, "owners": { "type": "array", "metadata": { "description": "List of AAD object IDs that is assigned Owner role at the resource group", "strongType": "PrincipalId" } } }, "resourceGroups": { "storageRG": { "description": "Contains the resource template deployment and a role assignment." } } } } ================================================ FILE: scripts/blueprints/sample-blueprint/blueprintAssignment.json ================================================ { "properties": { "blueprintId": "/providers/Microsoft.Management/managementGroups/{YourMG}/providers/Microsoft.Blueprint/blueprints/MyBlueprint", "resourceGroups": { "storageRG": { "name": "StorageAccount", "location": "eastus2" } }, "parameters": { "storageAccountType": { "value": "Standard_GRS" }, "tagName": { "value": "CostCenter" }, "tagValue": { "value": "ContosoIT" }, "contributors": { "value": [ "7be2f100-3af5-4c15-bcb7-27ee43784a1f", "38833b56-194d-420b-90ce-cff578296714" ] }, "owners": { "value": [ "44254d2b-a0c7-405f-959c-f829ee31c2e7", "316deb5f-7187-4512-9dd4-21e7798b0ef9" ] } } }, "identity": { "type": "systemAssigned" }, "location": "westus" } ================================================ FILE: scripts/blueprints/warner-azure-blueprints.ps1 ================================================ # Getting Started with Azure Blueprints # Tim Warner (techtrainertim.com) # Ref: https://timw.info/f88be # Authenticate to Azure Connect-AzAccount Set-AzContext -SubscriptionName 'Microsoft Azure Sponsorship' # Get Azure Blueprints module Install-Module -Name Az.Blueprint -Force ; Update-Help -ErrorAction SilentlyContinue # Get a reference to the sample blueprint object $blueprint = New-AzBlueprint -Name 'MyBlueprint' -BlueprintFile .\blueprint.json # Add artifacts New-AzBlueprintArtifact -Blueprint $blueprint -Name 'roleContributor' -ArtifactFile .\artifacts\roleContributor.json New-AzBlueprintArtifact -Blueprint $blueprint -Name 'policyTags' -ArtifactFile .\artifacts\policyTags.json New-AzBlueprintArtifact -Blueprint $blueprint -Name 'policyStorageTags' -ArtifactFile .\artifacts\policyStorageTags.json New-AzBlueprintArtifact -Blueprint $blueprint -Type TemplateArtifact -Name 'templateStorage' -TemplateFile .\artifacts\templateStorage.json -TemplateParameterFile .\artifacts\templateStorageParams.json -ResourceGroupName storageRG New-AzBlueprintArtifact -Blueprint $blueprint -Name 'roleOwner' -ArtifactFile .\artifacts\roleOwner.json # Publish the blueprint Publish-AzBlueprint -Blueprint $blueprint -Version '1.0.0.0' # Assign the blueprint New-AzBlueprintAssignment -Blueprint $blueprint -Name 'assignMyBlueprint' -AssignmentFile .\blueprintAssignment.json # Unassign the blueprint Remove-AzBlueprintAssignment -Name 'assignMyBlueprint' ================================================ FILE: scripts/key-vault.azcli ================================================ # Manage Key Vault with CLI # Ref: timw.info/1fg # Preliminary info az login az configure az account set --name "Microsoft Azure Sponsorship" az account list -o table # Add a secret az keyvault secret set --vault-name "twaz500vault1" --name "VMPassword" --value "hVFkk965BuUv " # View secrets az keyvault secret list --vault-name "twaz500vault1" # Retrieve a secret az keyvault secret show --name "VMPassword" --vault-name "" --query "value" # Register service principal az ad sp create-for-rbac -n "KeyVaultSP" --password "hVFkk965BuUv" --role Contributor # If you don't specify a password, one will be created for you # Allow SP to read secrets az keyvault set-policy --name "twaz500vault1" --spn 8f8c4bbd-485b-45fd-98f7-ec6300b7b4ed --secret-permissions get ================================================ FILE: scripts/powershell/Dockerfile.txt ================================================ # Dockerfile needs that name with no extension in root of build folder. # Sample Dockerfile # Indicates that the windowsservercore image will be used as the base image. FROM mcr.microsoft.com/windows/servercore:ltsc2019 # Metadata indicating an image maintainer. LABEL maintainer="jshelton@contoso.com" # Uses dism.exe to install the IIS role. RUN dism.exe /online /enable-feature /all /featurename:iis-webserver /NoRestart # Creates an HTML file and adds content to this file. RUN echo "Hello World - Dockerfile" > c:\inetpub\wwwroot\index.html # Sets a command or process that will run each time a container is run from the new image. CMD [ "cmd" ] # Build process docker build -t iis-image-name . # Run process # Another Dockerfile #Step 1: Start from base image mcr.microsoft.com/windows/servercore FROM mcr.microsoft.com/windows/servercore #Step 2: Create temporary directory to hold SQL Server 2016 installation files RUN powershell -Command (mkdir C:\SQL2016Dev_SP2) #Step 3: Copy SQL Server 2016 installation files from the host to the container image COPY \SQL2016Dev_SP2 C:/SQL2016Dev_SP2 #Step 4: Install SQL Server 2016 via command line RUN C:/SQL2016Dev_SP2/SETUP.exe /Q /ACTION=INSTALL /FEATURES=SQLENGINE /INSTANCENAME=MSSQLSERVER /SECURITYMODE=SQL /SAPWD="y0urSecUr3PAssw0rd" /SQLSVCACCOUNT="NT AUTHORITY\System" /AGTSVCACCOUNT="NT AUTHORITY\System" /SQLSYSADMINACCOUNTS="BUILTIN\Administrators" /IACCEPTSQLSERVERLICENSETERMS=1 /TCPENABLED=1 /UPDATEENABLED=False #Step 5: Set SQL Server service to automatic RUN powershell -Command (Set-Service MSSQLSERVER -StartupType Automatic) #Step 6: Remove SQL Server installation media folder RUN powershell -Command (Remove-Item -Path C:/SQL2016Dev_SP2 -Recurse -Force) #Step 7: Switch shell to PowerShell in preparation for running script Start.ps1 SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] #Step 8: Copy Start.ps1 to image on root directory COPY \start.ps1 / #Step 9: Set current working directory for script execution WORKDIR / #Step 10: Run PowerShell script Start.ps1, passing the -ACCEPT_EULA parameter with a value of Y CMD .\start.ps1 -ACCEPT_EULA "Y" -Verbose ================================================ FILE: scripts/powershell/Update-AutomationAzureModulesForAccount.ps1 ================================================ <# Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. #> <# .SYNOPSIS Update Azure PowerShell modules in an Azure Automation account. .DESCRIPTION This Azure Automation runbook updates Azure PowerShell modules imported into an Azure Automation account with the module versions published to the PowerShell Gallery. Prerequisite: an Azure Automation account with an Azure Run As account credential. .PARAMETER ResourceGroupName The Azure resource group name. .PARAMETER AutomationAccountName The Azure Automation account name. .PARAMETER SimultaneousModuleImportJobCount (Optional) The maximum number of module import jobs allowed to run concurrently. .PARAMETER AzureModuleClass (Optional) The class of module that will be updated (AzureRM or Az) If set to Az, this script will rely on only Az modules to update other modules. Set this to Az if your runbooks use only Az modules to avoid conflicts. .PARAMETER AzureEnvironment (Optional) Azure environment name. .PARAMETER Login (Optional) If $false, do not login to Azure. .PARAMETER ModuleVersionOverrides (Optional) Module versions to use instead of the latest on the PowerShell Gallery. If $null, the currently published latest versions will be used. If not $null, must contain a JSON-serialized dictionary, for example: '{ "AzureRM.Compute": "5.8.0", "AzureRM.Network": "6.10.0" }' or @{ 'AzureRM.Compute'='5.8.0'; 'AzureRM.Network'='6.10.0' } | ConvertTo-Json .PARAMETER PsGalleryApiUrl (Optional) PowerShell Gallery API URL. .LINK https://docs.microsoft.com/en-us/azure/automation/automation-update-azure-modules #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param( [Parameter(Mandatory = $true)] [string] $ResourceGroupName, [Parameter(Mandatory = $true)] [string] $AutomationAccountName, [int] $SimultaneousModuleImportJobCount = 10, [string] $AzureModuleClass = 'AzureRM', [string] $AzureEnvironment = 'AzureCloud', [bool] $Login = $true, [string] $ModuleVersionOverrides = $null, [string] $PsGalleryApiUrl = 'https://www.powershellgallery.com/api/v2' ) $ErrorActionPreference = "Continue" #region Constants $script:AzureRMProfileModuleName = "AzureRM.Profile" $script:AzureRMAutomationModuleName = "AzureRM.Automation" $script:GetAzureRmAutomationModule = "Get-AzureRmAutomationModule" $script:NewAzureRmAutomationModule = "New-AzureRmAutomationModule" $script:AzAccountsModuleName = "Az.Accounts" $script:AzAutomationModuleName = "Az.Automation" $script:GetAzAutomationModule = "Get-AzAutomationModule" $script:NewAzAutomationModule = "New-AzAutomationModule" $script:AzureSdkOwnerName = "azure-sdk" #endregion #region Functions function ConvertJsonDictTo-HashTable($JsonString) { try{ $JsonObj = ConvertFrom-Json $JsonString -ErrorAction Stop } catch [System.ArgumentException] { throw "Unable to deserialize the JSON string for parameter ModuleVersionOverrides: ", $_ } $Result = @{} foreach ($Property in $JsonObj.PSObject.Properties) { $Result[$Property.Name] = $Property.Value } $Result } # Use the Run As connection to login to Azure function Login-AzureAutomation([bool] $AzModuleOnly) { try { $RunAsConnection = Get-AutomationConnection -Name "AzureRunAsConnection" Write-Output "Logging in to Azure ($AzureEnvironment)..." if (!$RunAsConnection.ApplicationId) { $ErrorMessage = "Connection 'AzureRunAsConnection' is incompatible type." throw $ErrorMessage } if ($AzModuleOnly) { Connect-AzAccount ` -ServicePrincipal ` -TenantId $RunAsConnection.TenantId ` -ApplicationId $RunAsConnection.ApplicationId ` -CertificateThumbprint $RunAsConnection.CertificateThumbprint ` -Environment $AzureEnvironment Select-AzSubscription -SubscriptionId $RunAsConnection.SubscriptionID | Write-Verbose } else { Add-AzureRmAccount ` -ServicePrincipal ` -TenantId $RunAsConnection.TenantId ` -ApplicationId $RunAsConnection.ApplicationId ` -CertificateThumbprint $RunAsConnection.CertificateThumbprint ` -Environment $AzureEnvironment Select-AzureRmSubscription -SubscriptionId $RunAsConnection.SubscriptionID | Write-Verbose } } catch { if (!$RunAsConnection) { $RunAsConnection | fl | Write-Output Write-Output $_.Exception $ErrorMessage = "Connection 'AzureRunAsConnection' not found." throw $ErrorMessage } throw $_.Exception } } # Checks the PowerShell Gallery for the latest available version for the module function Get-ModuleDependencyAndLatestVersion([string] $ModuleName) { $ModuleUrlFormat = "$PsGalleryApiUrl/Search()?`$filter={1}&searchTerm=%27{0}%27&targetFramework=%27%27&includePrerelease=false&`$skip=0&`$top=40" $ForcedModuleVersion = $ModuleVersionOverridesHashTable[$ModuleName] $CurrentModuleUrl = if ($ForcedModuleVersion) { $ModuleUrlFormat -f $ModuleName, "Version%20eq%20'$ForcedModuleVersion'" } else { $ModuleUrlFormat -f $ModuleName, 'IsLatestVersion' } $SearchResult = Invoke-RestMethod -Method Get -Uri $CurrentModuleUrl -UseBasicParsing if (!$SearchResult) { Write-Verbose "Could not find module $ModuleName on PowerShell Gallery. This may be a module you imported from a different location. Ignoring this module" } else { if ($SearchResult.Length -and $SearchResult.Length -gt 1) { $SearchResult = $SearchResult | Where-Object { $_.title.InnerText -eq $ModuleName } } if (!$SearchResult) { Write-Verbose "Could not find module $ModuleName on PowerShell Gallery. This may be a module you imported from a different location. Ignoring this module" } else { $PackageDetails = Invoke-RestMethod -Method Get -UseBasicParsing -Uri $SearchResult.id # Ignore the modules that are not published as part of the Azure SDK if ($PackageDetails.entry.properties.Owners -ne $script:AzureSdkOwnerName) { Write-Warning "Module : $ModuleName is not part of azure sdk. Ignoring this." } else { $ModuleVersion = $PackageDetails.entry.properties.version $Dependencies = $PackageDetails.entry.properties.dependencies @($ModuleVersion, $Dependencies) } } } } function Get-ModuleContentUrl($ModuleName) { $ModuleContentUrlFormat = "$PsGalleryApiUrl/package/{0}" $VersionedModuleContentUrlFormat = "$ModuleContentUrlFormat/{1}" $ForcedModuleVersion = $ModuleVersionOverridesHashTable[$ModuleName] if ($ForcedModuleVersion) { $VersionedModuleContentUrlFormat -f $ModuleName, $ForcedModuleVersion } else { $ModuleContentUrlFormat -f $ModuleName } } # Imports the module with given version into Azure Automation function Import-AutomationModule([string] $ModuleName, [bool] $UseAzModule = $false) { $NewAutomationModule = $null $GetAutomationModule = $null if ($UseAzModule) { $GetAutomationModule = $script:GetAzAutomationModule $NewAutomationModule = $script:NewAzAutomationModule } else { $GetAutomationModule = $script:GetAzureRmAutomationModule $NewAutomationModule = $script:NewAzureRmAutomationModule } $LatestModuleVersionOnGallery = (Get-ModuleDependencyAndLatestVersion $ModuleName)[0] $ModuleContentUrl = Get-ModuleContentUrl $ModuleName # Find the actual blob storage location of the module do { $ModuleContentUrl = (Invoke-WebRequest -Uri $ModuleContentUrl -MaximumRedirection 0 -UseBasicParsing -ErrorAction Ignore).Headers.Location } while (!$ModuleContentUrl.Contains(".nupkg")) $CurrentModule = & $GetAutomationModule ` -Name $ModuleName ` -ResourceGroupName $ResourceGroupName ` -AutomationAccountName $AutomationAccountName if ($CurrentModule.Version -eq $LatestModuleVersionOnGallery) { Write-Output "Module : $ModuleName is already present with version $LatestModuleVersionOnGallery. Skipping Import" } else { Write-Output "Importing $ModuleName module of version $LatestModuleVersionOnGallery to Automation" & $NewAutomationModule ` -ResourceGroupName $ResourceGroupName ` -AutomationAccountName $AutomationAccountName ` -Name $ModuleName ` -ContentLink $ModuleContentUrl > $null } } # Parses the dependency got from PowerShell Gallery and returns name and version function GetModuleNameAndVersionFromPowershellGalleryDependencyFormat([string] $Dependency) { if ($null -eq $Dependency) { throw "Improper dependency format" } $Tokens = $Dependency -split":" if ($Tokens.Count -ne 3) { throw "Improper dependency format" } $ModuleName = $Tokens[0] $ModuleVersion = $Tokens[1].Trim("[","]") @($ModuleName, $ModuleVersion) } # Validates if the given list of modules has already been added to the module import map function AreAllModulesAdded([string[]] $ModuleListToAdd) { $Result = $true foreach ($ModuleToAdd in $ModuleListToAdd) { $ModuleAccounted = $false # $ModuleToAdd is specified in the following format: # ModuleName:ModuleVersionSpecification: # where ModuleVersionSpecification follows the specifiation # at https://docs.microsoft.com/en-us/nuget/reference/package-versioning#version-ranges-and-wildcards # For example: # AzureRm.profile:[4.0.0]: # or # AzureRm.profile:3.0.0: # In any case, the dependency version specification is always separated from the module name with # the ':' character. The explicit intent of this runbook is to always install the latest module versions, # so we want to completely ignore version specifications here. $ModuleNameToAdd = $ModuleToAdd -replace '\:.*', '' foreach($AlreadyIncludedModules in $ModuleImportMapOrder) { if ($AlreadyIncludedModules -contains $ModuleNameToAdd) { $ModuleAccounted = $true break } } if (!$ModuleAccounted) { $Result = $false break } } $Result } # Creates a module import map. This is a 2D array of strings so that the first # element in the array consist of modules with no dependencies. # The second element only depends on the modules in the first element, the # third element only dependes on modules in the first and second and so on. function Create-ModuleImportMapOrder([bool] $AzModuleOnly) { $ModuleImportMapOrder = $null $ProfileOrAccountsModuleName = $null $GetAutomationModule = $null # Use the relevant module class to avoid conflicts if ($AzModuleOnly) { $ProfileOrAccountsModuleName = $script:AzAccountsModuleName $GetAutomationModule = $script:GetAzAutomationModule } else { $ProfileOrAccountsModuleName = $script:AzureRmProfileModuleName $GetAutomationModule = $script:GetAzureRmAutomationModule } # Get all the non-conflicting modules in the current automation account $CurrentAutomationModuleList = & $GetAutomationModule ` -ResourceGroupName $ResourceGroupName ` -AutomationAccountName $AutomationAccountName | ?{ ($AzModuleOnly -and ($_.Name -eq 'Az' -or $_.Name -like 'Az.*')) -or (!$AzModuleOnly -and ($_.Name -eq 'AzureRM' -or $_.Name -like 'AzureRM.*' -or $_.Name -eq 'Azure' -or $_.Name -like 'Azure.*')) } # Get the latest version of the AzureRM.Profile OR Az.Accounts module $VersionAndDependencies = Get-ModuleDependencyAndLatestVersion $ProfileOrAccountsModuleName $ModuleEntry = $ProfileOrAccountsModuleName $ModuleEntryArray = ,$ModuleEntry $ModuleImportMapOrder += ,$ModuleEntryArray do { $NextAutomationModuleList = $null $CurrentChainVersion = $null # Add it to the list if the modules are not available in the same list foreach ($Module in $CurrentAutomationModuleList) { $Name = $Module.Name Write-Verbose "Checking dependencies for $Name" $VersionAndDependencies = Get-ModuleDependencyAndLatestVersion $Module.Name if ($null -eq $VersionAndDependencies) { continue } $Dependencies = $VersionAndDependencies[1].Split("|") $AzureModuleEntry = $Module.Name # If the previous list contains all the dependencies then add it to current list if ((-not $Dependencies) -or (AreAllModulesAdded $Dependencies)) { Write-Verbose "Adding module $Name to dependency chain" $CurrentChainVersion += ,$AzureModuleEntry } else { # else add it back to the main loop variable list if not already added if (!(AreAllModulesAdded $AzureModuleEntry)) { Write-Verbose "Module $Name does not have all dependencies added as yet. Moving module for later import" $NextAutomationModuleList += ,$Module } } } $ModuleImportMapOrder += ,$CurrentChainVersion $CurrentAutomationModuleList = $NextAutomationModuleList } while ($null -ne $CurrentAutomationModuleList) $ModuleImportMapOrder } # Wait and confirm that all the modules in the list have been imported successfully in Azure Automation function Wait-AllModulesImported( [Collections.Generic.List[string]] $ModuleList, [int] $Count, [bool] $UseAzModule = $false) { $GetAutomationModule = if ($UseAzModule) { $script:GetAzAutomationModule } else { $script:GetAzureRmAutomationModule } $i = $Count - $SimultaneousModuleImportJobCount if ($i -lt 0) { $i = 0 } for ( ; $i -lt $Count; $i++) { $Module = $ModuleList[$i] Write-Output ("Checking import Status for module : {0}" -f $Module) while ($true) { $AutomationModule = & $GetAutomationModule ` -Name $Module ` -ResourceGroupName $ResourceGroupName ` -AutomationAccountName $AutomationAccountName $IsTerminalProvisioningState = ($AutomationModule.ProvisioningState -eq "Succeeded") -or ($AutomationModule.ProvisioningState -eq "Failed") if ($IsTerminalProvisioningState) { break } Write-Verbose ("Module {0} is getting imported" -f $Module) Start-Sleep -Seconds 30 } if ($AutomationModule.ProvisioningState -ne "Succeeded") { Write-Error ("Failed to import module : {0}. Status : {1}" -f $Module, $AutomationModule.ProvisioningState) } else { Write-Output ("Successfully imported module : {0}" -f $Module) } } } # Uses the module import map created to import modules. # It will only import modules from an element in the array if all the modules # from the previous element have been added. function Import-ModulesInAutomationAccordingToDependency([string[][]] $ModuleImportMapOrder, [bool] $UseAzModule) { foreach($ModuleList in $ModuleImportMapOrder) { $i = 0 Write-Output "Importing Array of modules : $ModuleList" foreach ($Module in $ModuleList) { Write-Verbose ("Importing module : {0}" -f $Module) Import-AutomationModule -ModuleName $Module -UseAzModule $UseAzModule $i++ if ($i % $SimultaneousModuleImportJobCount -eq 0) { # It takes some time for the modules to start getting imported. # Sleep for sometime before making a query to see the status Start-Sleep -Seconds 20 Wait-AllModulesImported -ModuleList $ModuleList -Count $i -UseAzModule $UseAzModule } } if ($i -lt $SimultaneousModuleImportJobCount) { Start-Sleep -Seconds 20 Wait-AllModulesImported -ModuleList $ModuleList -Count $i -UseAzModule $UseAzModule } } } function Update-ProfileAndAutomationVersionToLatest([string] $AutomationModuleName) { # Get the latest azure automation module version $VersionAndDependencies = Get-ModuleDependencyAndLatestVersion $AutomationModuleName # Automation only has dependency on profile $ModuleDependencies = GetModuleNameAndVersionFromPowershellGalleryDependencyFormat $VersionAndDependencies[1] $ProfileModuleName = $ModuleDependencies[0] # Create web client object for downloading data $WebClient = New-Object System.Net.WebClient # Download AzureRM.Profile to temp location $ModuleContentUrl = Get-ModuleContentUrl $ProfileModuleName $ProfileURL = (Invoke-WebRequest -Uri $ModuleContentUrl -MaximumRedirection 0 -UseBasicParsing -ErrorAction Ignore).Headers.Location $ProfilePath = Join-Path $env:TEMP ($ProfileModuleName + ".zip") $WebClient.DownloadFile($ProfileURL, $ProfilePath) # Download AzureRM.Automation to temp location $ModuleContentUrl = Get-ModuleContentUrl $AutomationModuleName $AutomationURL = (Invoke-WebRequest -Uri $ModuleContentUrl -MaximumRedirection 0 -UseBasicParsing -ErrorAction Ignore).Headers.Location $AutomationPath = Join-Path $env:TEMP ($AutomationModuleName + ".zip") $WebClient.DownloadFile($AutomationURL, $AutomationPath) # Create folder for unzipping the Module files $PathFolderName = New-Guid $PathFolder = Join-Path $env:TEMP $PathFolderName # Unzip files $ProfileUnzipPath = Join-Path $PathFolder $ProfileModuleName Expand-Archive -Path $ProfilePath -DestinationPath $ProfileUnzipPath -Force $AutomationUnzipPath = Join-Path $PathFolder $AutomationModuleName Expand-Archive -Path $AutomationPath -DestinationPath $AutomationUnzipPath -Force # Import modules Import-Module (Join-Path $ProfileUnzipPath ($ProfileModuleName + ".psd1")) -Force -Verbose Import-Module (Join-Path $AutomationUnzipPath ($AutomationModuleName + ".psd1")) -Force -Verbose } #endregion #region Main body if ($ModuleVersionOverrides) { $ModuleVersionOverridesHashTable = ConvertJsonDictTo-HashTable $ModuleVersionOverrides } else { $ModuleVersionOverridesHashTable = @{} } $UseAzModule = $null $AutomationModuleName = $null # We want to support updating Az modules. This means this runbook should support upgrading using only Az modules if ($AzureModuleClass -eq "Az") { $UseAzModule = $true $AutomationModuleName = $script:AzAutomationModuleName } elseif ( $AzureModuleClass -eq "AzureRM") { $UseAzModule = $false $AutomationModuleName = $script:AzureRMAutomationModuleName } else { Write-Error "Invalid AzureModuleClass: '$AzureModuleClass'. Must be either Az or AzureRM" -ErrorAction Stop } # Import the latest version of the Az automation and accounts version to the local sandbox Update-ProfileAndAutomationVersionToLatest $AutomationModuleName if ($Login) { Login-AzureAutomation $UseAzModule } $ModuleImportMapOrder = Create-ModuleImportMapOrder $UseAzModule Import-ModulesInAutomationAccordingToDependency $ModuleImportMapOrder $UseAzModule #endregion ================================================ FILE: scripts/powershell/aad-pim-powershell.ps1 ================================================ # install Azure PowerShell Install-Module -Name Az -Verbose # install Azure AD module Install-Module -Name AzureADPreview -Verbose Import-Module -Name AzureADPreview # connect to Azure and AAD Connect-AzAccount Connect-AzureAD # get AAD PIM commands Get-Command -Noun AzureADMSPriv* Get-AzureADMSPrivilegedRoleDefinition -ProviderId aadRoles -ResourceId 926d99e7-117c-4a6a-8031-0cc481e9da26 # MS PIM module https://timw.info/5ut # install the module Install-Module -Name Microsoft.Azure.ActiveDirectory.PIM.PSModule -force -allowclobber # import and view commands & help Import-Module -Name Microsoft.Azure.ActiveDirectory.PIM.PSModule Get-Command -Module Microsoft.Azure.ActiveDirectory.PIM.PSModule Tutorial: https://timw.info/14r ================================================ FILE: scripts/powershell/app-gateway-e2e-tls.ps1 ================================================ <# End-to-End TLS for Application Gateway Ref: timw.info/ys2 Note: This is only a partial procedure #> # Configure the certificate for the application gateway. This certificate is used to decrypt and reencrypt the traffic on the application gateway. $passwd = ConvertTo-SecureString -AsPlainText -Force $cert = New-AzApplicationGatewaySSLCertificate -Name cert01 -CertificateFile -Password $passwd # Create the HTTP listener for the application gateway. Assign the front-end IP configuration, port, and TLS/SSL certificate to use. $listener = New-AzApplicationGatewayHttpListener -Name listener01 -Protocol Https -FrontendIPConfiguration $fipconfig -FrontendPort $fp -SSLCertificate $cert # V1: Upload the certificate to be used on the TLS-enabled back-end pool resources. The certificate provided in the previous step should be the public key of the .pfx certificate present on the back end. $authcert = New-AzApplicationGatewayAuthenticationCertificate -Name 'allowlistcert1' -CertificateFile C:\cert.cer # V2: create a trusted root certificate instead of an authentication certificate $trustedRootCert01 = New-AzApplicationGatewayTrustedRootCertificate -Name "test1" -CertificateFile # Configure the HTTP settings for the application gateway back end. Assign the certificate uploaded in the preceding step to the HTTP settings. $poolSetting01 = New-AzApplicationGatewayBackendHttpSettings -Name “setting01” -Port 443 -Protocol Https -CookieBasedAffinity Disabled -TrustedRootCertificate $trustedRootCert01 -HostName "test1" ================================================ FILE: scripts/powershell/application-security-groups.ps1 ================================================ # create the ASGs $webAsg = New-AzApplicationSecurityGroup -ResourceGroupName 'Load-Balancer' -Name webASG -Location 'eastus2' # Assign vNICs to ASG $webNic = Get-AzNetworkInterface -Name 'myNIC0' -ResourceGroupName 'Load-Balancer' $webNic.IpConfigurations[0].ApplicationSecurityGroups = $webAsg Set-AzNetworkInterface -NetworkInterface $webNic $webNic = Get-AzNetworkInterface -Name 'myNIC1' -ResourceGroupName 'Load-Balancer' $webNic.IpConfigurations[0].ApplicationSecurityGroups = $webAsg Set-AzNetworkInterface -NetworkInterface $webNic ================================================ FILE: scripts/powershell/azcopy.txt ================================================ # Use AzCopy # Ref: https://timw.info/d0a73 # Sign in (you can also use SAS tokens and managed identities) azcopy login --tenant-id= # Create a container azcopy make 'https://mystorageaccount.blob.core.windows.net/mycontainer' # Upload a file azcopy copy 'C:\myDirectory\myTextFile.txt' 'https://mystorageaccount.blob.core.windows.net/mycontainer/myTextFile.txt' # Upload files azcopy copy 'C:\myDirectory' 'https://mystorageaccount.blob.core.windows.net/mycontainer' --include-path 'photos;documents\myFile.txt' --recursive # Copy a blob to another storage account azcopy copy 'https://mysourceaccount.blob.core.windows.net/mycontainer/myTextFile.txt?sv=2018-03-28&ss=bfqt&srt=sco&sp=rwdlacup&se=2019-07-04T05:30:08Z&st=2019-07-03T21:30:08Z&spr=https&sig=CAfhgnc9gdGktvB=ska7bAiqIddM845yiyFwdMH481QA8%3D' 'https://mydestinationaccount.blob.core.windows.net/mycontainer/myTextFile.txt' # Copy all containers and blobs to another storage account azcopy copy 'https://mysourceaccount.blob.core.windows.net/?sv=2018-03-28&ss=bfqt&srt=sco&sp=rwdlacup&se=2019-07-04T05:30:08Z&st=2019-07-03T21:30:08Z&spr=https&sig=CAfhgnc9gdGktvB=ska7bAiqIddM845yiyFwdMH481QA8%3D' 'https://mydestinationaccount.blob.core.windows.net' --recursive ================================================ FILE: scripts/powershell/azure-key-vault-powershell.ps1 ================================================ <# Work with Azure Key Vault and PowerShell Ref: https://docs.microsoft.com/en-us/azure/key-vault/quick-create-powershell #> # Set up environment Login-AzAccount New-AzResourceGroup -Name ContosoResourceGroup -Location EastUS New-AzKeyVault -Name 'Contoso-Vault2' -ResourceGroupName 'ContosoResourceGroup' -Location 'East US' # Convert a plaintext secret to a secure string $secretvalue = ConvertTo-SecureString 'hVFkk965BuUv' -AsPlainText -Force # Store the secret in key vault $secret = Set-AzKeyVaultSecret -VaultName 'ContosoKeyVault' -Name 'ExamplePassword' -SecretValue $secretvalue # Retrieve the key value (Get-AzKeyVaultSecret -vaultName "Contosokeyvault" -name "ExamplePassword").SecretValueText # Clean up the environment Remove-AzResourceGroup -Name ContosoResourceGroup ================================================ FILE: scripts/powershell/azuresql-database-tde.ps1 ================================================ # Set variables $resourceGroup = '' $dbServerName = '' $dbName = '' $keyVaultName = '' $keyVaultKeyId = (Get-AzureKeyVaultKey -VaultName '' -Name '').Id # Add a service principal for SQL server $server = Set-AzSqlServer -ResourceGroupName $resourceGroup -ServerName $dbServerName -AssignIdentity # Grand key vault permissions to server Set-AzKeyVaultAccessPolicy -VaultName $keyVaultName ` -ObjectId $server.Identity.PrincipalId -PermissionsToKeys get, wrapKey, unwrapKey # add the key from Key Vault to the server Add-AzSqlServerKeyVaultKey -ResourceGroupName $resourceGroup -ServerName $dbServerName -KeyId $keyVaultKeyId # set the key as the TDE protector for all resources under the server Set-AzSqlServerTransparentDataEncryptionProtector -ResourceGroupName $resourceGroup -ServerName $dbServerName ` -Type AzureKeyVault -KeyId $keyVaultKeyId # confirm the TDE protector was configured as intended Get-AzSqlServerTransparentDataEncryptionProtector -ResourceGroupName $resourceGroup -ServerName $dbServerName # Enable TDE Set-AzSqlDatabaseTransparentDataEncryption -ResourceGroupName $resourceGroup ` -ServerName $dbServerName -DatabaseName $dbName -State "Enabled" # Check encryption state # get the encryption state Get-AzSqlDatabaseTransparentDataEncryption -ResourceGroupName $resourceGroup ` -ServerName $dbServerName -DatabaseName $dbName ` # check the encryption progress for a database or data warehouse Get-AzSqlDatabaseTransparentDataEncryptionActivity -ResourceGroupName $resourceGroup ` -ServerName $dbServerName -DatabaseName $dbName # Turn off TDE Set-AzSqlDatabaseTransparentDataEncryption -ServerName $dbServerName -ResourceGroupName $resourceGroup ` -DatabaseName $dbName -State "Disabled" ================================================ FILE: scripts/powershell/backup-key-vault.ps1 ================================================ Get-Command -Module Az.KeyVault Backup-AzKeyVaultSecret -VaultName 'MyKeyVault' -Name 'MySecret' -OutputFile 'C:\Backup.blob' -Force ================================================ FILE: scripts/powershell/convert-vhd.ps1 ================================================ # Convert VHDX to VHD Convert-VHD -Path 'C:\users\public\Documents\Hyper-V\Virtual hard disks\win16template.vhdx' -DestinationPath 'c:\VHD\win16template.vhd' -Verbose # Launch Sysprep Start-Process -FilePath 'C:\Windows\System32\Sysprep\sysprep.exe' # Upload to Azure blob storage ================================================ FILE: scripts/powershell/cosmos-container-rbac.ps1 ================================================ # Ref: https://docs.microsoft.com/en-us/azure/cosmos-db/how-to-setup-rbac # Install PowerShell Core Install-Module -Name PSReleaseTools Get-PSCore # Install Azure PowerShell Install-Module -Name Az -Verbose Update-Help # Get Cosmos DB preview module Find-Module -Name Az.CosmosDB -AllowPrerelease Install-Module -Name Az.CosmosDB -Verbose -Force # Sign into Azure Connect-AzAccount Set-AzContext -SubscriptionName '' # RO $resourceGroupName = "dp201" $accountName = "twdp201cosmos" New-AzCosmosDBSqlRoleDefinition -AccountName $accountName ` -ResourceGroupName $resourceGroupName ` -Type CustomRole -RoleName MyReadOnlyRole ` -DataAction @( ` 'Microsoft.DocumentDB/databaseAccounts/readMetadata', 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read', ` 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/executeQuery', ` 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/readChangeFeed') ` -AssignableScope "/" # RW New-AzCosmosDBSqlRoleDefinition -AccountName $accountName ` -ResourceGroupName $resourceGroupName ` -Type CustomRole -RoleName MyReadWriteRole ` -DataAction @( ` 'Microsoft.DocumentDB/databaseAccounts/readMetadata', 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*', ` 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*') ` -AssignableScope "/" #acct or /dbs/db/colls/container # Fetch role IDs Get-AzCosmosDBSqlRoleDefinition -AccountName $accountName ` -ResourceGroupName $resourceGroupName # Assign a role $readOnlyRoleDefinitionId = "" # as fetched above $principalId = "" #object ID New-AzCosmosDBSqlRoleAssignment -AccountName $accountName ` -ResourceGroupName $resourceGroupName ` -RoleDefinitionId $readOnlyRoleDefinitionId ` -Scope $accountName ` -PrincipalId $principalId ================================================ FILE: scripts/powershell/create-aks-cluster.ps1 ================================================ Ref 1: https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough # Create resource group az group create --name aks --location eastus # Create cluster az aks create --resource-group aks --name oreillyAKS --node-count 1 --enable-addons monitoring --generate-ssh-keys <# SSH key files '/home/tim/.ssh/id_rsa' and '/home/tim/.ssh/id_rsa.pub' have been generated under ~/.ssh to allow SSH access to the VM. If using machines without permanent storage like Azure Cloud Shell without an attached file share, back up your keys to a safe location #> # Connect to the cluster az aks install-cli az aks get-credentials --resource-group aks --name oreillyAKS kubectl get nodes # Deploy the application (YAML is in cloud drive) kubectl apply -f azure-vote.yaml # Test the application (CTRL+C to stop) kubectl get service azure-vote-front --watch # Browse to load balancer external IP # Start the Kubernetes dashboard az aks browse --resource-group aks --name oreillyAKS # Sign into the dashboard (K8S 1.16+) kubectl create clusterrolebinding kubernetes-dashboard --clusterrole=cluster-admin --serviceaccount=kube-system:kubernetes-dashboard ## Update with your input. kubectl config view -o jsonpath='{.users[?(@.name == "clusterUser_aks_oreillyAKS")].user.auth-provider.config.access-token}' ================================================ FILE: scripts/powershell/create-azure-bastion.ps1 ================================================ # ref: https://timw.info/5ei # ref2: https://timw.info/p1c # Create delegated subnet $subnetName = "AzureBastionSubnet" $subnet = New-AzVirtualNetworkSubnetConfig -Name $subnetName -AddressPrefix 10.0.0.0/24 $vnet = New-AzVirtualNetwork -Name "myVnet" -ResourceGroupName "myBastionRG" -Location "westeurope" -AddressPrefix 10.0.0.0/16 -Subnet $subnet # Create public IP $publicip = New-AzPublicIpAddress -ResourceGroupName "myBastionRG" -name "myPublicIP" -location "westeurope" -AllocationMethod Static -Sku Standard # Create Bastion $bastion = New-AzBastion -ResourceGroupName "myBastionRG" -Name "myBastion" -PublicIpAddress $publicip -VirtualNetwork $vnet ================================================ FILE: scripts/powershell/create-key-vault.ps1 ================================================ Get-AzContext | Format-List New-AzResourceGroup -Name 'cs' -Location EastUS New-AzKeyVault -Name 'cs-vault' -ResourceGroupName 'cs' -Location 'East US' Set-AzKeyVaultAccessPolicy -VaultName 'cs-vault' ` -UserPrincipalName 'tim@timw.info' ` -PermissionsToSecrets get, set, delete $secretvalue = ConvertTo-SecureString '?!hVFkk965BuUv!?' -AsPlainText -Force $secretset = Set-AzKeyVaultSecret -VaultName 'cs-vault' ` -Name 'cs-password' -SecretValue $secretvalue $secretget = Get-AzKeyVaultSecret -VaultName 'cs-vault' -Name 'ExamplePassword' $ssPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secret.SecretValue) try { $secretValueText = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ssPtr) } finally { [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ssPtr) } Write-Output $secretValueText ================================================ FILE: scripts/powershell/custom-azure-rbac-role.ps1 ================================================ # Ref: https://docs.microsoft.com/en-us/azure/role-based-access-control/tutorial-custom-role-powershell Get-AzProviderOperation 'Microsoft.Storage/*' | Format-Table -Property Operation, Description -AutoSize Get-AzRoleDefinition -Name 'Virtual Machine Contributor' | ConvertTo-Json | Out-File 'D:\vmcontrib.json' code D:\vmcontrib.json Get-AzSubscription | Select-Object -Property id New-AzRoleDefinition -InputFile 'D:\vmcontrib.json' Get-AzRoleDefinition | Where-Object -FilterScript { $_.IsCustom -eq $true } | Format-Table -Property Name, IsCustom Get-AzRoleDefinition 'Help Desk Support' | Remove-AzRoleDefinition -Force Get-AzRoleDefinition | Where-Object { $_.IsCustom -eq $true } | Remove-AzRoleDefinition -Force Remove-AzRoleDefinition -Id '22222222-2222-2222-2222-222222222222' ================================================ FILE: scripts/powershell/custom-rbac-role.ps1 ================================================ # Ref: https://docs.microsoft.com/en-us/azure/role-based-access-control/tutorial-custom-role-powershell # ARM REST API Ref: https://docs.microsoft.com/en-us/rest/api/azure/ Get-AzProviderOperation 'Microsoft.Network/*' | Format-Table -Property Operation, Description -AutoSize Get-AzRoleDefinition -Name 'Virtual Machine Contributor' | ConvertTo-Json | Out-File 'D:\vmc2022.json' Get-AzSubscription -SubscriptionName 'Microsoft Azure Sponsorship' | Select-Object -Property id # 2fbf906e-1101-4bc0-b64f-adc44e462fff New-AzRoleDefinition -InputFile 'D:\vmc2022.json' Get-AzRoleDefinition | Where-Object -FilterScript { $_.IsCustom -eq $true } | Format-Table -Property Name, IsCustom Get-AzRoleDefinition 'VM Admnistrator' | Remove-AzRoleDefinition -Force Get-AzRoleDefinition | ? { $_.IsCustom -eq $true } | Remove-AzRoleDefinition -Force Remove-AzRoleDefinition -Id 'fb31d481-00fd-4214-8f47-c030bcc59099' ================================================ FILE: scripts/powershell/customscriptextension.ps1 ================================================ $fileUri = @("https://xxxxxxx.blob.core.windows.net/buildServer1/1_Add_Tools.ps1", "https://xxxxxxx.blob.core.windows.net/buildServer1/2_Add_Features.ps1", "https://xxxxxxx.blob.core.windows.net/buildServer1/3_CompleteInstall.ps1") $settings = @{"fileUris" = $fileUri}; $storageAcctName = "xxxxxxx" $storageKey = "1234ABCD" $protectedSettings = @{"storageAccountName" = $storageAcctName; "storageAccountKey" = $storageKey; "commandToExecute" = "powershell -ExecutionPolicy Unrestricted -File 1_Add_Tools.ps1"}; #run command Set-AzVMExtension -ResourceGroupName ` -Location ` -VMName ` -Name "buildserver1" ` -Publisher "Microsoft.Compute" ` -ExtensionType "CustomScriptExtension" ` -TypeHandlerVersion "1.10" ` -Settings $settings ` -ProtectedSettings $protectedSettings ` ================================================ FILE: scripts/powershell/enable-azuresql-database-tde.ps1 ================================================ EXECUTE sp_set_database_firewall_rule N'my_db_rule'; ,'168.0.0.0' ,'168.0.0.0' -- Enable Azure connections. EXECUTE sp_set_database_firewall_rule N'Allow Azure', '0.0.0.0', '0.0.0.0'; -- Create database-level firewall setting for only IP 0.0.0.4 EXECUTE sp_set_database_firewall_rule N'Example DB Setting 1', '0.0.0.4', '0.0.0.4'; -- Update database-level firewall setting to create a range of allowed IP addresses EXECUTE sp_set_database_firewall_rule N'Example DB Setting 1', '0.0.0.4', '0.0.0.6'; ================================================ FILE: scripts/powershell/enforce-tag-value-rg.json ================================================ { "properties": { "displayName": "Enforce tag and its value on resource groups", "description": "Enforces a required tag and its value on resource groups.", "mode": "All", "parameters": { "tagName": { "type": "String", "metadata": { "description": "Name of the tag, such as costCenter" } }, "tagValue": { "type": "String", "metadata": { "description": "Value of the tag, such as headquarters" } } }, "policyRule": { "if": { "allOf": [ { "field": "type", "equals": "Microsoft.Resources/subscriptions/resourceGroups" }, { "not": { "field": "[concat('tags[',parameters('tagName'), ']')]", "equals": "[parameters('tagValue')]" } } ] }, "then": { "effect": "deny" } } } } ================================================ FILE: scripts/powershell/installWebServer.ps1 ================================================ Install-WindowsFeature -name Web-Server -IncludeManagementTools ================================================ FILE: scripts/powershell/linux-vm-ssh-keys.ps1 ================================================ # Linux VM / SSH Keys # Generate SSH key pair ssh-keygen -t rsa -b 2048 # Display your public key cat ~/.ssh/id_rsa.pub # SSH into your VM ssh user@vmaddress # Quick create VM # Create a subnet configuration $subnetConfig = New-AzVirtualNetworkSubnetConfig ` -Name "mySubnet" ` -AddressPrefix 192.168.1.0/24 # Create a virtual network $vnet = New-AzVirtualNetwork ` -ResourceGroupName "myResourceGroup" ` -Location "EastUS" ` -Name "myVNET" ` -AddressPrefix 192.168.0.0/16 ` -Subnet $subnetConfig # Create a public IP address and specify a DNS name $pip = New-AzPublicIpAddress ` -ResourceGroupName "myResourceGroup" ` -Location "EastUS" ` -AllocationMethod Static ` -IdleTimeoutInMinutes 4 ` -Name "mypublicdns$(Get-Random)" # Create an inbound network security group rule for port 22 $nsgRuleSSH = New-AzNetworkSecurityRuleConfig ` -Name "myNetworkSecurityGroupRuleSSH" ` -Protocol "Tcp" ` -Direction "Inbound" ` -Priority 1000 ` -SourceAddressPrefix * ` -SourcePortRange * ` -DestinationAddressPrefix * ` -DestinationPortRange 22 ` -Access "Allow" # Create an inbound network security group rule for port 80 $nsgRuleWeb = New-AzNetworkSecurityRuleConfig ` -Name "myNetworkSecurityGroupRuleWWW" ` -Protocol "Tcp" ` -Direction "Inbound" ` -Priority 1001 ` -SourceAddressPrefix * ` -SourcePortRange * ` -DestinationAddressPrefix * ` -DestinationPortRange 80 ` -Access "Allow" # Create a network security group $nsg = New-AzNetworkSecurityGroup ` -ResourceGroupName "myResourceGroup" ` -Location "EastUS" ` -Name "myNetworkSecurityGroup" ` -SecurityRules $nsgRuleSSH, $nsgRuleWeb # Create a virtual network card and associate with public IP address and NSG $nic = New-AzNetworkInterface ` -Name "myNic" ` -ResourceGroupName "myResourceGroup" ` -Location "EastUS" ` -SubnetId $vnet.Subnets[0].Id ` -PublicIpAddressId $pip.Id ` -NetworkSecurityGroupId $nsg.Id # Define a credential object $securePassword = ConvertTo-SecureString ' ' -AsPlainText -Force $cred = New-Object System.Management.Automation.PSCredential ("azureuser", $securePassword) # Create a virtual machine configuration $vmConfig = New-AzVMConfig ` -VMName "myVM" ` -VMSize "Standard_D1" | ` Set-AzVMOperatingSystem ` -Linux ` -ComputerName "myVM" ` -Credential $cred ` -DisablePasswordAuthentication | ` Set-AzVMSourceImage ` -PublisherName "Canonical" ` -Offer "UbuntuServer" ` -Skus "16.04-LTS" ` -Version "latest" | ` Add-AzVMNetworkInterface ` -Id $nic.Id # Configure the SSH key $sshPublicKey = cat ~/.ssh/id_rsa.pub Add-AzVMSshPublicKey ` -VM $vmconfig ` -KeyData $sshPublicKey ` -Path "/home/azureuser/.ssh/authorized_keys" New-AzVM ` -ResourceGroupName "myResourceGroup" ` -Location eastus -VM $vmConfig # Connect to the VM Get-AzPublicIpAddress -ResourceGroupName "myResourceGroup" | Select "IpAddress" ssh azureuser@10.111.12.123 # Install a web server sudo apt-get -y update sudo apt-get -y install nginx # Browser to http://pubip ================================================ FILE: scripts/powershell/managed-storage-account.ps1 ================================================ #Prefix for resources $prefix = "tlw704" #Basic variables $location = "eastus" $id = Get-Random -Minimum 1000 -Maximum 9999 #Create a resource group for Key Vault $keyVaultGroup = New-AzResourceGroup -Name "$prefix-key-vault-$id" -Location $location #Create a new Key Vault $keyVaultParameters = @{ Name = "$prefix-key-vault-$id" ResourceGroupName = $keyVaultGroup.ResourceGroupName Location = $location Sku = "Standard" } $keyVault = New-AzKeyVault @keyVaultParameters #Grant yourself access to the Key Vault # Give your user principal access to all storage account permissions, on your Key Vault instance $accessPolicy = @{ VaultName = $keyVault.Name UserPrincipalName = "tim@timw.info" PermissionsToStorage = ("get","list","listsas","delete","set","update","regeneratekey","recover","backup","restore","purge") } Set-AzKeyVaultAccessPolicy @accessPolicy $keyVault | Format-List #Create a new storage account $saAccountParameters = @{ Name = "$($prefix)sa$id" ResourceGroupName = $keyVaultGroup.ResourceGroupName Location = $location SkuName = "Standard_LRS" } $storageAccount = New-AzStorageAccount @saAccountParameters Get-AzStorageAccountKey -ResourceGroupName $storageAccount.ResourceGroupName -Name $storageAccount.StorageAccountName $keyVaultSpAppId = "cfa8b339-82a2-471a-a3c9-0fc0be7a4093" New-AzRoleAssignment -ApplicationId $keyVaultSpAppId -RoleDefinitionName 'Storage Account Key Operator Service Role' -Scope $storageAccount.Id # Add your storage account to your Key Vault's managed storage accounts list $managedStorageAccount = @{ VaultName = $keyVault.VaultName AccountName = $storageAccount.StorageAccountName AccountResourceId = $storageAccount.Id ActiveKeyName = "key1" RegenerationPeriod = [System.Timespan]::FromDays(90) } Add-AzKeyVaultManagedStorageAccount @managedStorageAccount Get-AzKeyVaultManagedStorageAccount -VaultName $keyVault.VaultName # Regenerate keys and set key1 as active key Update-AzKeyVaultManagedStorageAccountKey -VaultName $keyVault.VaultName -AccountName $storageAccount.StorageAccountName -KeyName "key1" ================================================ FILE: scripts/powershell/networking.ps1 ================================================ # Azure Networking ###### CREATE NEW MULTI-TIER VNET ###### # Variables for common values $rgName='MyResourceGroup' $location='eastus' # Create user object $cred = Get-Credential -Message "Enter a username and password for the virtual machine." # Create a resource group. New-AzResourceGroup -Name $rgName -Location $location # Create a virtual network with a front-end subnet and back-end subnet. $fesubnet = New-AzVirtualNetworkSubnetConfig -Name 'MySubnet-FrontEnd' -AddressPrefix '10.0.1.0/24' $besubnet = New-AzVirtualNetworkSubnetConfig -Name 'MySubnet-BackEnd' -AddressPrefix '10.0.2.0/24' $vnet = New-AzVirtualNetwork -ResourceGroupName $rgName -Name 'MyVnet' -AddressPrefix '10.0.0.0/16' ` -Location $location -Subnet $fesubnet, $besubnet # Create an NSG rule to allow HTTP traffic in from the Internet to the front-end subnet. $rule1 = New-AzNetworkSecurityRuleConfig -Name 'Allow-HTTP-All' -Description 'Allow HTTP' ` -Access Allow -Protocol Tcp -Direction Inbound -Priority 100 ` -SourceAddressPrefix Internet -SourcePortRange * ` -DestinationAddressPrefix * -DestinationPortRange 80 # Create an NSG rule to allow RDP traffic from the Internet to the front-end subnet. $rule2 = New-AzNetworkSecurityRuleConfig -Name 'Allow-RDP-All' -Description "Allow RDP" ` -Access Allow -Protocol Tcp -Direction Inbound -Priority 200 ` -SourceAddressPrefix Internet -SourcePortRange * ` -DestinationAddressPrefix * -DestinationPortRange 3389 # Create a network security group for the front-end subnet. $nsgfe = New-AzNetworkSecurityGroup -ResourceGroupName $RgName -Location $location ` -Name 'MyNsg-FrontEnd' -SecurityRules $rule1,$rule2 # Associate the front-end NSG to the front-end subnet. Set-AzVirtualNetworkSubnetConfig -VirtualNetwork $vnet -Name 'MySubnet-FrontEnd' ` -AddressPrefix '10.0.1.0/24' -NetworkSecurityGroup $nsgfe # Create an NSG rule to allow SQL traffic from the front-end subnet to the back-end subnet. $rule1 = New-AzNetworkSecurityRuleConfig -Name 'Allow-SQL-FrontEnd' -Description "Allow SQL" ` -Access Allow -Protocol Tcp -Direction Inbound -Priority 100 ` -SourceAddressPrefix '10.0.1.0/24' -SourcePortRange * ` -DestinationAddressPrefix * -DestinationPortRange 1433 # Create an NSG rule to allow RDP traffic from the Internet to the back-end subnet. $rule2 = New-AzNetworkSecurityRuleConfig -Name 'Allow-RDP-All' -Description "Allow RDP" ` -Access Allow -Protocol Tcp -Direction Inbound -Priority 200 ` -SourceAddressPrefix Internet -SourcePortRange * ` -DestinationAddressPrefix * -DestinationPortRange 3389 # Create a network security group for back-end subnet. $nsgbe = New-AzNetworkSecurityGroup -ResourceGroupName $RgName -Location $location ` -Name "MyNsg-BackEnd" -SecurityRules $rule1,$rule2 # Associate the back-end NSG to the back-end subnet Set-AzVirtualNetworkSubnetConfig -VirtualNetwork $vnet -Name 'MySubnet-BackEnd' ` -AddressPrefix '10.0.2.0/24' -NetworkSecurityGroup $nsgbe # Create a public IP address for the web server VM. $publicipvm1 = New-AzPublicIpAddress -ResourceGroupName $rgName -Name 'MyPublicIp-Web' ` -location $location -AllocationMethod Dynamic # Create a NIC for the web server VM. $nicVMweb = New-AzNetworkInterface -ResourceGroupName $rgName -Location $location ` -Name 'MyNic-Web' -PublicIpAddress $publicipvm1 -NetworkSecurityGroup $nsgfe -Subnet $vnet.Subnets[0] # Create a Web Server VM in the front-end subnet $vmConfig = New-AzVMConfig -VMName 'MyVm-Web' -VMSize 'Standard_DS2' | ` Set-AzVMOperatingSystem -Windows -ComputerName 'MyVm-Web' -Credential $cred | ` Set-AzVMSourceImage -PublisherName 'MicrosoftWindowsServer' -Offer 'WindowsServer' ` -Skus '2016-Datacenter' -Version latest | Add-AzVMNetworkInterface -Id $nicVMweb.Id $vmweb = New-AzVM -ResourceGroupName $rgName -Location $location -VM $vmConfig # Create a public IP address for the SQL VM. $publicipvm2 = New-AzPublicIpAddress -ResourceGroupName $rgName -Name MyPublicIP-Sql ` -location $location -AllocationMethod Dynamic # Create a NIC for the SQL VM. $nicVMsql = New-AzNetworkInterface -ResourceGroupName $rgName -Location $location ` -Name MyNic-Sql -PublicIpAddress $publicipvm2 -NetworkSecurityGroup $nsgbe -Subnet $vnet.Subnets[1] # Create a SQL VM in the back-end subnet. $vmConfig = New-AzVMConfig -VMName 'MyVm-Sql' -VMSize 'Standard_DS2' | ` Set-AzVMOperatingSystem -Windows -ComputerName 'MyVm-Sql' -Credential $cred | ` Set-AzVMSourceImage -PublisherName 'MicrosoftSQLServer' -Offer 'SQL2016-WS2016' ` -Skus 'Web' -Version latest | Add-AzVMNetworkInterface -Id $nicVMsql.Id $vmsql = New-AzVM -ResourceGroupName $rgName -Location $location -VM $vmConfig # Create an NSG rule to block all outbound traffic from the back-end subnet to the Internet (must be done after VM creation) $rule3 = New-AzNetworkSecurityRuleConfig -Name 'Deny-Internet-All' -Description "Deny Internet All" ` -Access Deny -Protocol Tcp -Direction Outbound -Priority 300 ` -SourceAddressPrefix * -SourcePortRange * ` -DestinationAddressPrefix Internet -DestinationPortRange * # Add NSG rule to Back-end NSG $nsgbe.SecurityRules.add($rule3) Set-AzNetworkSecurityGroup -NetworkSecurityGroup $nsgb###### CREATE NEW ###### PIER TWO VNETS ###### # Variables for common values $rgName = 'MyResourceGroup' $location = 'eastus' # Create a resource group. New-AzResourceGroup -Name $rgName -Location $location # Create virtual network 1. $vnet1 = New-AzVirtualNetwork -ResourceGroupName $rgName -Name 'Vnet1' -AddressPrefix '10.0.0.0/16' -Location $location # Create virtual network 2. $vnet2 = New-AzVirtualNetwork -ResourceGroupName $rgName -Name 'Vnet2' -AddressPrefix '10.1.0.0/16' -Location $location # Peer VNet1 to VNet2. Add-AzVirtualNetworkPeering -Name 'LinkVnet1ToVnet2' -VirtualNetwork $vnet1 -RemoteVirtualNetworkId $vnet2.Id # Peer VNet2 to VNet1. Add-AzVirtualNetworkPeering -Name 'LinkVnet2ToVnet1' -VirtualNetwork $vnet2 -RemoteVirtualNetworkId $vnet1.Id ================================================ FILE: scripts/powershell/password-reset.ps1 ================================================ net user tim P@$$w0rd123! New-Item -Name 'extension.txt' -Path 'C:\' -ItemType File -Value 'It works.' -Force ================================================ FILE: scripts/powershell/policy-enforce-tag-value-rg.json ================================================ { "properties": { "displayName": "Enforce tag and its value on resource groups", "description": "Enforces a required tag and its value on resource groups.", "mode": "All", "parameters": { "tagName": { "type": "String", "metadata": { "description": "Name of the tag, such as costCenter" } }, "tagValue": { "type": "String", "metadata": { "description": "Value of the tag, such as headquarters" } } }, "policyRule": { "if": { "allOf": [ { "field": "type", "equals": "Microsoft.Resources/subscriptions/resourceGroups" }, { "not": { "field": "[concat('tags[',parameters('tagName'), ']')]", "equals": "[parameters('tagValue')]" } } ] }, "then": { "effect": "deny" } } } } ================================================ FILE: scripts/powershell/powershell-key-vault.ps1 ================================================ # PowerShell Key Vault (Ref: https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-powershell) # Convert a secret to a secure string $secretvalue = ConvertTo-SecureString 'hVFkk965BuUv' -AsPlainText -Force # Create a secret $secret = Set-AzKeyVaultSecret -VaultName 'oreilly-vault-001' ` -Name 'ExamplePassword' -SecretValue $secretvalue # View the secret in plain text (Get-AzKeyVaultSecret -vaultName "oreilly-vault-001" -name "ExamplePassword").SecretValueText ================================================ FILE: scripts/powershell/storage-account.ps1 ================================================ # Azure Storage Accounts # List storage accounts Get-AzStorageAccount | Select StorageAccountName, Location # Retrieve an existing storage account $resourceGroup = "myexistingresourcegroup" $storageAccountName = "myexistingstorageaccount" $storageAccount = Get-AzStorageAccount -ResourceGroupName $resourceGroup ` -Name $storageAccountName # Create a storage account # Get list of locations and select one. Get-AzLocation | select Location $location = "eastus" # Create a new resource group. $resourceGroup = "teststoragerg" New-AzResourceGroup -Name $resourceGroup -Location $location # Set the name of the storage account and the SKU name. $storageAccountName = "testpshstorage" $skuName = "Standard_LRS" # Create the storage account. $storageAccount = New-AzStorageAccount -ResourceGroupName $resourceGroup ` -Name $storageAccountName ` -Location $location ` -SkuName $skuName # Retrieve the context. $ctx = $storageAccount.Context # Manage access keys $storageAccountKey = ` (Get-AzStorageAccountKey ` -ResourceGroupName $resourceGroup ` -Name $storageAccountName).Value[0] # Regenerate the key New-AzStorageAccountKey -ResourceGroupName $resourceGroup ` -Name $storageAccountName ` -KeyName key1 # Delete the storage account Remove-AzStorageAccount -ResourceGroup $resourceGroup -AccountName $storageAccountName ================================================ FILE: scripts/powershell/taxonomic-tags.ps1 ================================================ # Resource Groups and Taxonomic Tags # See existing tags on a resource group (Get-AzResourceGroup -Name 'oreilly').Tags # See existing tags for a particular resource (Get-AzResource -ResourceId /subscriptions//resourceGroups/oreilly/providers/Microsoft.Storage/storageAccounts/).Tags # See existing tags for a named resource (Get-AzResource -ResourceName 'oreilly-keyvault1' -ResourceGroupName 'oreilly').Tags # Get resource groups that have a specific tag (Get-AzResourceGroup -Tag @{ Dept = "Finance" }).ResourceGroupName # Get resources that have a specific tag (Get-AzResource -Tag @{ Dept = "Finance" }).Name # Get resources that have a specific tag name (Get-AzResource -TagName Dept).Name # Add tags to RG without existing tags Set-AzResourceGroup -Name oreilly -Tag @{ Dept = "IT"; Environment = "Test" } # Add tags to RG that has existing tags $tags = (Get-AzResourceGroup -Name oreilly).Tags $tags.Add("Status", "Approved") Set-AzResourceGroup -Tag $tags -Name oreilly # Apply tags from an RG to its resources, preserving existing tags $group = Get-AzResourceGroup "oreilly" if ($null -ne $group.Tags) { $resources = Get-AzResource -ResourceGroupName $group.ResourceGroupName foreach ($r in $resources) { $resourcetags = (Get-AzResource -ResourceId $r.ResourceId).Tags if ($resourcetags) { foreach ($key in $group.Tags.Keys) { if (-not($resourcetags.ContainsKey($key))) { $resourcetags.Add($key, $group.Tags[$key]) } } Set-AzResource -Tag $resourcetags -ResourceId $r.ResourceId -Force } else { Set-AzResource -Tag $group.Tags -ResourceId $r.ResourceId -Force } } } # Remove all tags Set-AzResourceGroup -Tag @{ } -Name oreilly ================================================ FILE: scripts/powershell/validate-deploy-arm-template.ps1 ================================================ Set-Location -Path '~\azure-admin-crash-course\101-storage-account-create' code .\azuredeploy.json code .\azuredeploy.parameters.json Test-AzResourceGroupDeployment -ResourceGroupName oreilly -Mode Incremental -TemplateFile .\azuredeploy.json -TemplateParameterFile New-AzResourceGroupDeployment -Name 'deploy-storage-account' ` -ResourceGroupName oreilly ` -Mode Incremental ` -TemplateParameterFile '.\azuredeploy.json' ` -Verbose ================================================ FILE: scripts/powershell/vm-key-vault.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "value": "tim" }, "adminPassword": { "reference": { "keyVault": { "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/INSTRUCTOR/providers/Microsoft.KeyVault/vaults/TimKV" }, "secretName": "vm-password" } }, "dnsLabelPrefix": { "value": "newvm79347a" } } } ================================================ FILE: scripts/powershell/vm-key-vault.template.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "type": "string", "defaultValue": "tim", "metadata": { "description": "Username for the Virtual Machine." } }, "adminPassword": { "type": "securestring", "metadata": { "description": "Password for the Virtual Machine." } }, "dnsLabelPrefix": { "type": "string", "metadata": { "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." } }, "windowsOSVersion": { "type": "string", "defaultValue": "2019-Datacenter", "allowedValues": [ "2008-R2-SP1", "2012-Datacenter", "2012-R2-Datacenter", "2016-Nano-Server", "2016-Datacenter-with-Containers", "2016-Datacenter", "2019-Datacenter" ], "metadata": { "description": "The Windows version for the VM. This will pick a fully patched image of this given Windows version." } }, "vmSize": { "type": "string", "defaultValue": "Standard_A2_v2", "metadata": { "description": "Size of the virtual machine." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } } }, "variables": { "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'sawinvm')]", "nicName": "myVMNic", "addressPrefix": "10.0.0.0/16", "subnetName": "Subnet", "subnetPrefix": "10.0.0.0/24", "publicIPAddressName": "myPublicIP", "vmName": "SimpleWinVM", "virtualNetworkName": "MyVNET", "subnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), variables('subnetName'))]", "networkSecurityGroupName": "default-NSG" }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2018-11-01", "name": "[variables('storageAccountName')]", "location": "[parameters('location')]", "sku": { "name": "Standard_LRS" }, "kind": "Storage", "properties": {} }, { "type": "Microsoft.Network/publicIPAddresses", "apiVersion": "2018-11-01", "name": "[variables('publicIPAddressName')]", "location": "[parameters('location')]", "properties": { "publicIPAllocationMethod": "Dynamic", "dnsSettings": { "domainNameLabel": "[parameters('dnsLabelPrefix')]" } } }, { "comments": "Default Network Security Group for template", "type": "Microsoft.Network/networkSecurityGroups", "apiVersion": "2019-08-01", "name": "[variables('networkSecurityGroupName')]", "location": "[parameters('location')]", "properties": { "securityRules": [ { "name": "default-allow-3389", "properties": { "priority": 1000, "access": "Allow", "direction": "Inbound", "destinationPortRange": "3389", "protocol": "Tcp", "sourcePortRange": "*", "sourceAddressPrefix": "*", "destinationAddressPrefix": "*" } } ] } }, { "type": "Microsoft.Network/virtualNetworks", "apiVersion": "2018-11-01", "name": "[variables('virtualNetworkName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" ], "properties": { "addressSpace": { "addressPrefixes": [ "[variables('addressPrefix')]" ] }, "subnets": [ { "name": "[variables('subnetName')]", "properties": { "addressPrefix": "[variables('subnetPrefix')]", "networkSecurityGroup": { "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" } } } ] } }, { "type": "Microsoft.Network/networkInterfaces", "apiVersion": "2018-11-01", "name": "[variables('nicName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", "[resourceId('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" ], "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Dynamic", "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]" }, "subnet": { "id": "[variables('subnetRef')]" } } } ] } }, { "type": "Microsoft.Compute/virtualMachines", "apiVersion": "2018-10-01", "name": "[variables('vmName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]", "[resourceId('Microsoft.Network/networkInterfaces/', variables('nicName'))]" ], "properties": { "hardwareProfile": { "vmSize": "[parameters('vmSize')]" }, "osProfile": { "computerName": "[variables('vmName')]", "adminUsername": "[parameters('adminUsername')]", "adminPassword": "[parameters('adminPassword')]" }, "storageProfile": { "imageReference": { "publisher": "MicrosoftWindowsServer", "offer": "WindowsServer", "sku": "[parameters('windowsOSVersion')]", "version": "latest" }, "osDisk": { "createOption": "FromImage" }, "dataDisks": [ { "diskSizeGB": 1023, "lun": 0, "createOption": "Empty" } ] }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]" } ] }, "diagnosticsProfile": { "bootDiagnostics": { "enabled": true, "storageUri": "[reference(resourceId('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))).primaryEndpoints.blob]" } } } } ], "outputs": { "hostname": { "type": "string", "value": "[reference(variables('publicIPAddressName')).dnsSettings.fqdn]" } } } ================================================ FILE: scripts/powershell/vnet-peering.ps1 ================================================ <# VNet Peering with Azure PowerShell Ref: http://rb.gy/b2fonv #> # create a resource group New-AzResourceGroup -ResourceGroupName myResourceGroup -Location EastUS # create a virtual network $virtualNetwork1 = New-AzVirtualNetwork ` -ResourceGroupName myResourceGroup ` -Location EastUS ` -Name myVirtualNetwork1 ` -AddressPrefix 10.0.0.0/16 # Add VNet config $subnetConfig = Add-AzVirtualNetworkSubnetConfig ` -Name Subnet1 ` -AddressPrefix 10.0.0.0/24 ` -VirtualNetwork $virtualNetwork1 # Commit the config to the VNet $virtualNetwork1 | Set-AzVirtualNetwork # Create a second VNet $virtualNetwork2 = New-AzVirtualNetwork ` -ResourceGroupName myResourceGroup ` -Location EastUS ` -Name myVirtualNetwork2 ` -AddressPrefix 10.1.0.0/16 # Create the subnet configuration. $subnetConfig = Add-AzVirtualNetworkSubnetConfig ` -Name Subnet1 ` -AddressPrefix 10.1.0.0/24 ` -VirtualNetwork $virtualNetwork2 # Write the subnet configuration to the virtual network. $virtualNetwork2 | Set-AzVirtualNetwork # Create a peering Add-AzVirtualNetworkPeering ` -Name myVirtualNetwork1-myVirtualNetwork2 ` -VirtualNetwork $virtualNetwork1 ` -RemoteVirtualNetworkId $virtualNetwork2.Id Add-AzVirtualNetworkPeering ` -Name myVirtualNetwork2-myVirtualNetwork1 ` -VirtualNetwork $virtualNetwork2 ` -RemoteVirtualNetworkId $virtualNetwork1.Id # Get the peering status Get-AzVirtualNetworkPeering ` -ResourceGroupName myResourceGroup ` -VirtualNetworkName myVirtualNetwork1 ` | Select-Object PeeringState ================================================ FILE: scripts/powershell/webjob.ps1 ================================================ New-Item -Path D:\ -Name webjob.txt -Value "Hi there" ================================================ FILE: scripts/sql/azure-sql-database-firewall-rules.sql ================================================ EXECUTE sp_set_database_firewall_rule N'my_db_rule'; ,'168.0.0.0' ,'168.0.0.0' -- Enable Azure connections. EXECUTE sp_set_database_firewall_rule N'Allow Azure', '0.0.0.0', '0.0.0.0'; -- Create database-level firewall setting for only IP 0.0.0.4 EXECUTE sp_set_database_firewall_rule N'Example DB Setting 1', '0.0.0.4', '0.0.0.4'; -- Update database-level firewall setting to create a range of allowed IP addresses EXECUTE sp_set_database_firewall_rule N'Example DB Setting 1', '0.0.0.4', '0.0.0.6'; ================================================ FILE: scripts/sql/azure-sql-row-level-security.sql ================================================ -- Row-level security -- Ref: https://timw.info/zwx ================================================ FILE: scripts/sql/azuresql-database-firewall.sql ================================================ EXECUTE sp_set_database_firewall_rule N'my_db_rule'; ,'168.0.0.0' ,'168.0.0.0' -- Enable Azure connections. EXECUTE sp_set_database_firewall_rule N'Allow Azure', '0.0.0.0', '0.0.0.0'; -- Create database-level firewall setting for only IP 0.0.0.4 EXECUTE sp_set_database_firewall_rule N'Example DB Setting 1', '0.0.0.4', '0.0.0.4'; -- Update database-level firewall setting to create a range of allowed IP addresses EXECUTE sp_set_database_firewall_rule N'Example DB Setting 1', '0.0.0.4', '0.0.0.6'; ================================================ FILE: study-resources/AZ-500-Teaching-Punchlist.md ================================================ # AZ-500 Teaching Punchlist ## Segment 1: Identity and Access (10 AM - 11 AM) - **Manage Entra Identities** - Users, groups, external identities - Entra ID Protection: MFA, passwordless, Conditional Access - Single sign-on (SSO), OAuth, and app registrations - Privileged Identity Management (PIM), custom roles, and permissions ## Segment 2: Secure Storage (11 AM - 12 PM) - **Plan and Implement Storage Security** - Access control: Azure Blob, File, Table, Queue - Protect data: soft delete, versioning, immutable storage - Encryption: BYOK, double encryption, TDE (databases) - Auditing and compliance: Purview and dynamic masking ## Segment 3: Secure Compute (12 PM - 1 PM) - **Plan and Implement Compute Security** - Azure Bastion, Just-in-Time (JIT) VM access - AKS security: network isolation, monitoring, and authentication - Disk encryption: ADE, encryption at host, confidential disk encryption ## Segment 4: Monitoring and Security Operations (1 PM - 2 PM) - **Monitor and Secure Operations** - Microsoft Defender: Secure Score, compliance, and threat protection - Azure Key Vault: manage secrets, certificates, and keys - Azure Monitor: configure and evaluate alerts - Microsoft Sentinel: analytics, incidents, and automation ## Segment 5: Wrap-up and Q&A (2 PM - 3 PM) - **Q&A and Additional Topics** - Recap of key topics: identity, storage, compute, and monitoring - Answer audience questions - Explore real-world use cases and advanced scenarios ================================================ FILE: study-resources/AZ-500-cert-study-resources.md ================================================ # Exam AZ-500 Certification Study Resources Last updated: March 2024 ## Official Microsoft Learning Resources * [AZ-500 Exam Page](https://learn.microsoft.com/en-us/certifications/exams/az-500) * [Microsoft Learn AZ-500 Learning Paths](https://learn.microsoft.com/en-us/credentials/certifications/azure-security-engineer/) * [Official Microsoft Practice Assessment](https://learn.microsoft.com/en-us/credentials/certifications/azure-security-engineer/practice/assessment) * [Microsoft Security Technical Documentation](https://learn.microsoft.com/en-us/security/) * [Microsoft Security Blog](https://www.microsoft.com/security/blog/) * [Azure Security Center Documentation](https://learn.microsoft.com/en-us/azure/defender-for-cloud/) * [Microsoft Defender for Cloud Documentation](https://learn.microsoft.com/en-us/azure/defender-for-cloud/) * [Microsoft Sentinel Documentation](https://learn.microsoft.com/en-us/azure/sentinel/) ## Hands-on Labs & Practice * [Microsoft Learn Labs](https://learn.microsoft.com/en-us/training/paths/manage-security-operations/) * [Official AZ-500 Lab Exercises](https://microsoftlearning.github.io/AZ-500-AzureSecurityTechnologies/) * [Microsoft Azure Free Account](https://azure.microsoft.com/free/) * [Azure Citadel Security Labs](https://www.azurecitadel.com/security/) * [Azure Log Analytics Query Playground](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-tutorial) ## Practice Exams & Test Prep * [MeasureUp AZ-500 Practice Tests](https://www.measureup.com/az-500-microsoft-azure-security-technologies.html) * [Whizlabs AZ-500 Practice Tests](https://www.whizlabs.com/microsoft-azure-certification-az-500/) ## Essential Tools * [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/) * [Azure PowerShell](https://learn.microsoft.com/en-us/powershell/azure/) * [Azure Storage Explorer](https://azure.microsoft.com/features/storage-explorer/) * [Microsoft Entra ID Portal](https://entra.microsoft.com/) * Visual Studio Code Extensions: * [Azure Account](https://marketplace.visualstudio.com/items?itemName=ms-vscode.azure-account) * [Azure Security Center](https://marketplace.visualstudio.com/items?itemName=ms-azuresecurity.vscode-azuresecurity) * [Azure CLI Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.azurecli) * [PowerShell](https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell) ## Security Community Resources * [Microsoft Security Community](https://techcommunity.microsoft.com/t5/security-compliance-and-identity/ct-p/SecurityComplianceIdentity) * [Azure Security Center Community](https://techcommunity.microsoft.com/t5/azure-security-center/bd-p/AzureSecurityCenter) * [Microsoft Security Update Guide](https://msrc.microsoft.com/update-guide/) * [Azure Security Podcast](https://azsecuritypodcast.net/) ## Exam Preparation Tips * Focus on hands-on experience with Azure security features * Practice implementing security controls across different Azure services * Understand identity and access management deeply * Master Azure security tools and monitoring capabilities * Review real-world security scenarios and best practices ================================================ FILE: study-resources/AZ-500-course-plan.md ================================================ # AZ-500 Crash Course: Key Discussion and Demo Topics ## Course Structure - **Duration:** 5 hours (4 segments of ~1 hour each, 8 min break at the top of each hour) - **Focus:** Concise discussion and demos of core AZ-500 topics - **Style:** Interactive and practical --- ## 🔐 Segment 1: Secure Identity and Access (15-20%) - **🔑 Microsoft Entra Management** - Manage security controls for identity and access - Implement multi-factor authentication (MFA) - Configure Conditional Access policies - Plan and manage resources in Privileged Identity Management - **🗝️ Role Management** - Manage Azure built-in role assignments - Create and manage custom roles - Implement Microsoft Entra Permissions Management - **🔐 Application Access** - Manage access to enterprise applications in Microsoft Entra ID - Configure app registration permission scopes and consent - Manage and use service principals - Configure managed identities for Azure resources --- ## 🌐 Segment 2: Secure Networking (20–25%) - **🔒 Virtual Network Security** - Configure Network Security Groups (NSGs) and Application Security Groups (ASGs) - Manage networks with Azure Virtual Network Manager - Plan and implement user-defined routes (UDRs) - Configure VPN connectivity and peering - Implement Virtual WAN with secured virtual hub - Monitor security with Network Watcher - **🛡️ Private Access** - Plan and implement virtual network Service Endpoints - Configure Private Endpoints and Private Link services - Implement network integration for App Service and Functions - Configure network security for App Service Environment - Secure Azure SQL Managed Instance - **🚀 Public Access Security** - Implement TLS for applications - Configure Azure Firewall and Firewall Manager - Deploy Azure Application Gateway and Azure Front Door - Implement Web Application Firewall (WAF) - Deploy Azure DDoS Protection Standard --- ## 💾 Segment 3: Secure Compute, Storage, and Databases (20–25%) - **🖥️ Compute Security** - Configure remote access with Azure Bastion and just-in-time VM access - Secure Azure Kubernetes Service (AKS) - Configure security monitoring for containers (ACI, ACA) - Manage access to Azure Container Registry (ACR) - Implement disk encryption options - Secure Azure API Management - **🗄️ Storage Security** - Configure access control for storage accounts - Manage storage account access keys - Configure secure access for Azure Files and Blob Storage - Protect data with soft delete, backups, versioning, and immutable storage - Configure Bring Your Own Key (BYOK) - Enable double encryption at the Azure Storage infrastructure level - **📊 Database Security** - Enable Microsoft Entra database authentication - Configure database auditing and dynamic masking - Implement Transparent Data Encryption (TDE) - Configure Azure SQL Database Always Encrypted --- ## 🔍 Segment 4: Secure Azure using Microsoft Defender for Cloud and Microsoft Sentinel (30–35%) - **⚙️ Cloud Governance Policies** - Create and assign Azure Policy initiatives - Configure Key Vault network settings and access control - Manage certificates, secrets, and keys - Configure key rotation - Implement backup/recovery for sensitive data - Configure security controls for asset management - **🛠️ Security Posture Management** - Work with Microsoft Defender for Cloud Secure Score - Assess compliance against security frameworks - Manage compliance standards - Connect hybrid and multi-cloud environments - Implement Microsoft Defender External Attack Surface Management (EASM) - **🔒 Threat Protection** - Enable Microsoft Defender workload protection services - Configure Defender for Servers, Databases, and Storage - Implement agentless scanning for VMs - Configure Defender Vulnerability Management - Connect DevOps security for GitHub, Azure DevOps, and GitLab - **📈 Security Monitoring and Automation** - Manage security alerts in Defender for Cloud - Configure workflow automation - Set up data collection rules (DCRs) in Azure Monitor - Configure Microsoft Sentinel data connectors and analytics - Implement Microsoft Sentinel automation --- ## Resources - [🔗 Microsoft Learn AZ-500 Documentation](https://learn.microsoft.com/en-us/certifications/exams/az-500/) - [🛠️ GitHub for Azure Security](https://github.com/topics/azure-security) - [🎥 Azure Security Demos](https://azure.microsoft.com/en-us/resources/videos/) ### Good luck, and let's secure the cloud! 🚀 ## 🎯 Demo Scenario: Securing a Multi-tier Application Follow along with this scenario to practice key security concepts covered in the course. ### Scenario Overview You're a security engineer at Contoso Ltd, tasked with securing a new three-tier application: - Web frontend (Azure App Service) - API layer (Azure Functions) - Database (Azure SQL) ### 🔄 Implementation Steps #### 1. Identity & Access Setup (30 mins) - Configure Microsoft Entra authentication for the web app - Set up managed identities for service-to-service communication - Implement Conditional Access policy for admin access - Configure Privileged Identity Management for just-in-time admin access #### 2. Network Security (30 mins) - Create network isolation using VNets, NSGs, and ASGs - Implement Private Endpoints for the database - Set up Azure Application Gateway with WAF - Configure Azure Front Door with CDN #### 3. Data Protection (30 mins) - Enable TDE and Always Encrypted for sensitive data - Configure Key Vault with RBAC and network restrictions - Implement immutable storage and soft delete - Configure double encryption for storage #### 4. Security Monitoring & Protection (30 mins) - Set up Microsoft Defender for Cloud workload protections - Configure Microsoft Sentinel data connectors and analytics rules - Create automation workflows for common security incidents - Implement vulnerability scanning and management ### 🎯 Success Criteria - ✅ All services use managed identities for authentication - ✅ Private network connectivity between services - ✅ All sensitive data encrypted at rest and in transit - ✅ Comprehensive detection and response capabilities ## Additional Resources ### 🔨 Practice Labs - [Azure Security Labs on Microsoft Learn](https://learn.microsoft.com/en-us/certifications/exams/az-500) - [Whizlabs AZ-500 Hands-on Labs](https://www.whizlabs.com/blog/top-azure-hands-on-labs/) - [Azure GOAT - Vulnerable Azure Environment for Practice](https://github.com/Akriti-S/AzGOAT) - [425Show Secure Azure Function Samples](https://github.com/425show/SecureAzureFunctionMiW) ### 📚 Documentation - [Azure Security Best Practices](https://learn.microsoft.com/en-us/azure/security/fundamentals/best-practices-and-patterns) - [Microsoft Security Documentation](https://learn.microsoft.com/en-us/security/) - [Azure Architecture Center - Security](https://learn.microsoft.com/en-us/azure/architecture/framework/security/overview) ### 🎥 Video Resources - [Microsoft Security YouTube Channel](https://www.youtube.com/c/MicrosoftSecurity) - [Azure Security Center in Action](https://www.youtube.com/playlist?list=PLLasX02E8BPBxGouWlJV-u_XVcXfkdscl) ================================================ FILE: study-resources/README.md ================================================ # AZ-500 Study Resources This directory contains supplementary study materials for the AZ-500 Microsoft Azure Security Technologies exam. ## Contents - [Certification Study Resources](AZ-500-cert-study-resources.md) - Additional resources for exam preparation - [Course Plan](AZ-500-course-plan.md) - Detailed course plan and schedule - [Teaching Punchlist](AZ-500-Teaching-Punchlist.md) - Key topics and teaching notes ## How to Use These Resources These resources are designed to complement the main study guide found in the root README.md file. Use these materials for: 1. **Deeper dive** into specific topic areas 2. **Additional practice** beyond the official materials 3. **Structured learning plan** to pace your studies Remember to focus on the skills measured in the [official exam guide](https://learn.microsoft.com/en-us/credentials/certifications/resources/study-guides/az-500) as your primary reference. ================================================ FILE: templates/101-aci-vnet/README.md ================================================ # Create an Azure container group with VNet This template demonstrates a simple use case for deploying a container instance into an Azure virtual network. (https://docs.microsoft.com/en-us/azure/container-instances/container-instances-vnet). ================================================ FILE: templates/101-aci-vnet/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "vnetName": { "type": "string", "defaultValue": "aci-vnet", "metadata": { "description": "VNet name" } }, "vnetAddressPrefix": { "type": "string", "defaultValue": "10.0.0.0/16", "metadata": { "description": "Address prefix" } }, "subnetAddressPrefix": { "type": "string", "defaultValue": "10.0.0.0/24", "metadata": { "description": "Subnet prefix" } }, "subnetName": { "type": "string", "defaultValue": "aci-subnet", "metadata": { "description": "Subnet name" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } }, "containerGroupName": { "type": "string", "defaultValue": "aci-containergroup", "metadata": { "description": "Container group name" } }, "containerName": { "type": "string", "defaultValue": "aci-container", "metadata": { "description": "Container name" } }, "image": { "type": "string", "metadata": { "description": "Container image to deploy. Should be of the form accountName/imagename:tag for images stored in Docker Hub or a fully qualified URI for a private registry like the Azure Container Registry." }, "defaultValue": "microsoft/aci-helloworld" }, "port": { "type": "string", "metadata": { "description": "Port to open on the container." }, "defaultValue": "80" }, "cpuCores": { "type": "string", "metadata": { "description": "The number of CPU cores to allocate to the container. Must be an integer." }, "defaultValue": "1.0" }, "memoryInGb": { "type": "string", "metadata": { "description": "The amount of memory to allocate to the container in gigabytes." }, "defaultValue": "1.5" } }, "variables": { "networkProfileName": "aci-networkProfile", "interfaceConfigName": "eth0", "interfaceIpConfig": "ipconfigprofile1" }, "resources": [ { "type": "Microsoft.Network/virtualNetworks", "name": "[parameters('vnetName')]", "apiVersion": "2018-07-01", "location": "[parameters('location')]", "properties": { "addressSpace": { "addressPrefixes": [ "[parameters('vnetAddressPrefix')]" ] }, "subnets": [ { "name": "[parameters('subnetName')]", "properties": { "addressPrefix": "[parameters('subnetAddressPrefix')]", "delegations": [ { "name": "DelegationService", "properties": { "serviceName": "Microsoft.ContainerInstance/containerGroups" } } ] } } ] } }, { "name": "[variables('networkProfileName')]", "type": "Microsoft.Network/networkProfiles", "apiVersion": "2018-07-01", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/virtualNetworks', parameters('vnetName'))]" ], "properties": { "containerNetworkInterfaceConfigurations": [ { "name": "[variables('interfaceConfigName')]", "properties": { "ipConfigurations": [ { "name": "[variables('interfaceIpConfig')]", "properties": { "subnet": { "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), parameters('subnetName'))]" } } } ] } } ] } }, { "name": "[parameters('containerGroupName')]", "type": "Microsoft.ContainerInstance/containerGroups", "apiVersion": "2018-07-01", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/networkProfiles', variables('networkProfileName'))]" ], "properties": { "containers": [ { "name": "[parameters('containerName')]", "properties": { "image": "[parameters('image')]", "ports": [ { "port": "[parameters('port')]", "protocol": "Tcp" } ], "resources": { "requests": { "cpu": "[parameters('cpuCores')]", "memoryInGB": "[parameters('memoryInGb')]" } } } } ], "osType": "Linux", "networkProfile": { "Id": "[resourceId('Microsoft.Network/networkProfiles', variables('networkProfileName'))]" }, "restartPolicy": "Always" } } ], "outputs": { "containerIPv4Address": { "type": "string", "value": "[reference(resourceId('Microsoft.ContainerInstance/containerGroups/', parameters('containerGroupName'))).ipAddress.ip]" } } } ================================================ FILE: templates/101-aci-vnet/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "containerGroupName": { "value": "GEN-UNIQUE" } } } ================================================ FILE: templates/101-aci-vnet/metadata.json ================================================ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", "itemDisplayName": "Azure Container Instances - VNet", "description": "Deploy a container instance into an Azure virtual network.", "summary": "This template demonstrates how to create a container group with VNet.", "githubUsername": "tilnl", "dateUpdated": "2018-11-05" } ================================================ FILE: templates/101-aks/.ci_skip ================================================ ================================================ FILE: templates/101-aks/README.md ================================================ # Azure Container Service (AKS) This template deploys an **AKS cluster**. See https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough for a walkthrough. To use keys stored in keyvault, replace ```"value":""``` with a reference to keyvault in parameters file. For example: ```json "servicePrincipalClientSecret": { "reference": { "keyVault": { "id": "" }, "secretName": "" } } ``` ================================================ FILE: templates/101-aks/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.1", "parameters": { "clusterName": { "type": "string", "defaultValue":"aks101cluster", "metadata": { "description": "The name of the Managed Cluster resource." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "The location of the Managed Cluster resource." } }, "dnsPrefix": { "type": "string", "metadata": { "description": "Optional DNS prefix to use with hosted Kubernetes API server FQDN." } }, "osDiskSizeGB": { "type": "int", "defaultValue": 0, "metadata": { "description": "Disk size (in GB) to provision for each of the agent pool nodes. This value ranges from 0 to 1023. Specifying 0 will apply the default disk size for that agentVMSize." }, "minValue": 0, "maxValue": 1023 }, "agentCount": { "type": "int", "defaultValue": 3, "metadata": { "description": "The number of nodes for the cluster." }, "minValue": 1, "maxValue": 50 }, "agentVMSize": { "type": "string", "defaultValue": "Standard_DS2_v2", "metadata": { "description": "The size of the Virtual Machine." } }, "linuxAdminUsername": { "type": "string", "metadata": { "description": "User name for the Linux Virtual Machines." } }, "sshRSAPublicKey": { "type": "string", "metadata": { "description": "Configure all linux machines with the SSH RSA public key string. Your key should include three parts, for example 'ssh-rsa AAAAB...snip...UcyupgH azureuser@linuxvm'" } }, "servicePrincipalClientId": { "metadata": { "description": "Client ID (used by cloudprovider)" }, "type": "securestring" }, "servicePrincipalClientSecret": { "metadata": { "description": "The Service Principal Client Secret." }, "type": "securestring" }, "osType": { "type": "string", "defaultValue": "Linux", "allowedValues": [ "Linux" ], "metadata": { "description": "The type of operating system." } }, "kubernetesVersion": { "type": "string", "defaultValue": "1.12.6", "allowedValues": [ "1.10.13", "1.11.8", "1.12.6" ], "metadata": { "description": "The version of Kubernetes." } } }, "resources": [ { "apiVersion": "2018-03-31", "type": "Microsoft.ContainerService/managedClusters", "location": "[parameters('location')]", "name": "[parameters('clusterName')]", "properties": { "kubernetesVersion": "[parameters('kubernetesVersion')]", "dnsPrefix": "[parameters('dnsPrefix')]", "agentPoolProfiles": [ { "name": "agentpool", "osDiskSizeGB": "[parameters('osDiskSizeGB')]", "count": "[parameters('agentCount')]", "vmSize": "[parameters('agentVMSize')]", "osType": "[parameters('osType')]", "storageProfile": "ManagedDisks" } ], "linuxProfile": { "adminUsername": "[parameters('linuxAdminUsername')]", "ssh": { "publicKeys": [ { "keyData": "[parameters('sshRSAPublicKey')]" } ] } }, "servicePrincipalProfile": { "clientId": "[parameters('servicePrincipalClientId')]", "Secret": "[parameters('servicePrincipalClientSecret')]" } } } ], "outputs": { "controlPlaneFQDN": { "type": "string", "value": "[reference(parameters('clusterName')).fqdn]" } } } ================================================ FILE: templates/101-aks/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "clusterName": { "value": "GEN-UNIQUE" }, "dnsPrefix": { "value": "GEN-UNIQUE" }, "linuxAdminUsername": { "value": "GEN-UNIQUE" }, "sshRSAPublicKey": { "value": "GEN-SSH-PUB-KEY" }, "servicePrincipalClientId": { "value": "GEN-GUID" }, "servicePrincipalClientSecret": { "value": "GEN-UNIQUE" } } } ================================================ FILE: templates/101-aks/metadata.json ================================================ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", "itemDisplayName": "Azure Container Service (AKS)", "description": "Deploy a managed cluster with Azure Container Service (AKS)", "summary": "Deploy a managed cluster with Azure Container Service (AKS)", "githubUsername": "vyta", "dateUpdated": "2019-03-21" } ================================================ FILE: templates/101-application-gateway-v2-autoscale-create/README.md ================================================ # Create Application Gateway v2 This template deploys an Application Gateway v2 in a virtual network and sets up auto scaling properties and an HTTP load-balancing rule with public frontend. ================================================ FILE: templates/101-application-gateway-v2-autoscale-create/azuredeploy.json ================================================ { "$schema":"https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion":"1.0.0.0", "parameters":{ "virtualNetworkName":{ "type":"string", "defaultValue":"Application-Vnet", "metadata":{ "description":"Virtual Network name" } }, "vnetAddressPrefix":{ "type":"string", "defaultValue":"10.0.0.0/16", "metadata":{ "description":"Virtual Network address range" } }, "subnetName":{ "type":"string", "defaultValue":"ApplicationGatewaySubnet", "metadata":{ "description":"Name of the subnet" } }, "subnetPrefix":{ "type":"string", "defaultValue":"10.0.0.0/24", "metadata":{ "description":"Subnet address range" } }, "applicationGatewayName":{ "type":"string", "defaultValue":"applicationGatewayV2", "metadata":{ "description":"Application Gateway name" } }, "minCapacity":{ "type":"int", "defaultValue":2, "metadata":{ "description":"Minimum instance count for Application Gateway" } }, "frontendPort":{ "type":"int", "defaultValue":80, "metadata":{ "description":"Application Gateway Frontend port" } }, "backendPort":{ "type":"int", "defaultValue":80, "metadata":{ "description":"Application gateway Backend port" } }, "backendIPAddresses":{ "type":"array", "defaultValue":[ { "IpAddress":"10.0.0.4" }, { "IpAddress":"10.0.0.5" } ], "metadata":{ "description":"Back end pool ip addresses" } }, "cookieBasedAffinity":{ "type":"string", "allowedValues":[ "Enabled", "Disabled" ], "defaultValue":"Disabled", "metadata":{ "description":"Cookie based affinity" } }, "location":{ "type":"string", "defaultValue":"[resourceGroup().location]", "metadata":{ "description":"Location for all resources." } } }, "variables":{ "appGwPublicIpName":"[concat(parameters('applicationGatewayName'), '-pip')]", "appGwPublicIPRef":"[resourceId('Microsoft.Network/publicIPAddresses',variables('appGwPublicIpName'))]", "appGwSize":"Standard_v2", "subnetRef":"[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName'))]" }, "resources":[ { "apiVersion":"2018-08-01", "type":"Microsoft.Network/virtualNetworks", "name":"[parameters('virtualNetworkName')]", "location":"[parameters('location')]", "properties":{ "addressSpace":{ "addressPrefixes":[ "[parameters('vnetAddressPrefix')]" ] }, "subnets":[ { "name":"[parameters('subnetName')]", "properties":{ "addressPrefix":"[parameters('subnetPrefix')]" } } ] } }, { "apiVersion":"2018-08-01", "type":"Microsoft.Network/publicIPAddresses", "name":"[variables('appGwPublicIpName')]", "location":"[parameters('location')]", "sku":{ "name":"Standard" }, "properties":{ "publicIPAllocationMethod":"Static" } }, { "apiVersion":"2018-08-01", "name":"[parameters('applicationGatewayName')]", "type":"Microsoft.Network/applicationGateways", "location":"[parameters('location')]", "dependsOn":[ "[variables('appGwPublicIPRef')]", "[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]" ], "properties":{ "sku":{ "name":"[variables('appGwSize')]", "tier":"Standard_v2" }, "autoscaleConfiguration":{ "minCapacity":"[parameters('minCapacity')]" }, "gatewayIPConfigurations":[ { "name":"appGatewayIpConfig", "properties":{ "subnet":{ "id":"[variables('subnetRef')]" } } } ], "frontendIPConfigurations":[ { "name":"appGatewayFrontendIP", "properties":{ "PublicIPAddress":{ "id":"[variables('appGwPublicIpRef')]" } } } ], "frontendPorts":[ { "name":"appGatewayFrontendPort", "properties":{ "Port":"[parameters('frontendPort')]" } } ], "backendAddressPools":[ { "name":"appGatewayBackendPool", "properties":{ "BackendAddresses":"[parameters('backendIPAddresses')]" } } ], "backendHttpSettingsCollection":[ { "name":"appGatewayBackendHttpSettings", "properties":{ "Port":"[parameters('backendPort')]", "Protocol":"Http", "CookieBasedAffinity":"[parameters('cookieBasedAffinity')]" } } ], "httpListeners":[ { "name":"appGatewayHttpListener", "properties":{ "FrontendIpConfiguration":{ "Id":"[resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', parameters('applicationGatewayName'), 'appGatewayFrontendIP')]" }, "FrontendPort":{ "Id":"[resourceId('Microsoft.Network/applicationGateways/frontendPorts', parameters('applicationGatewayName'), 'appGatewayFrontendPort')]" }, "Protocol":"Http" } } ], "requestRoutingRules":[ { "Name":"rule1", "properties": { "RuleType": "Basic", "httpListener": { "id": "[resourceId('Microsoft.Network/applicationGateways/httpListeners', parameters('applicationGatewayName'), 'appGatewayHttpListener')]" }, "backendAddressPool": { "id": "[resourceId('Microsoft.Network/applicationGateways/backendAddressPools', parameters('applicationGatewayName'), 'appGatewayBackendPool')]" }, "backendHttpSettings": { "id": "[resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', parameters('applicationGatewayName'), 'appGatewayBackendHttpSettings')]" } } } ] } } ] } ================================================ FILE: templates/101-application-gateway-v2-autoscale-create/azuredeploy.parameters.json ================================================ { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "frontendPort": { "value": 80 }, "backendPort": { "value": 80 } } } ================================================ FILE: templates/101-application-gateway-v2-autoscale-create/metadata.json ================================================ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "itemDisplayName": "Create an Application Gateway v2", "description": "This template creates an application gateway v2 in a virtual network and sets up auto scaling properties and an HTTP load-balancing rule with public frontend", "summary": "Create an Application Gateway v2", "githubUsername": "vmehmeri", "type": "QuickStart", "dateUpdated": "2018-11-30" } ================================================ FILE: templates/101-functions-managed-identity/README.md ================================================ # Provision a function app on a consumption plan with managed identity enabled [![Deploy to Azure](https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/1-CONTRIBUTION-GUIDE/images/deploytoazure.png)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2F101-functions-managed-identity%2Fazuredeploy.json) [![Visualize](https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/1-CONTRIBUTION-GUIDE/images/visualizebutton.png)](http://armviz.io/#/?loadhttp://armviz.io/#/?load=https%3A%2F%2Fraw.githubusercontent.com%2Fazure%2Fazure-quickstart-templates%2Fmaster%2F101-functions-managed-identity%2Fazuredeploy.json) This template creates a function application on a consumption plan on Windows. It also enables managed identity for the application and returns the principal id as output. ## Managed identities in Azure Functions You can learn more about [managed identities](https://docs.microsoft.com/en-us/azure/app-service/overview-managed-identity) and common scenarios in the [documentation](https://docs.microsoft.com/en-us/azure/app-service/overview-managed-identity#obtaining-tokens-for-azure-resources). Another common scenario is to grant the managed identity access to either resource groups or subscriptions so that the function has permissions to take action on Azure resources. This is useful when using functions to automate Azure operational tasks. ## Grant the managed identity contributor access to the subscription or resource group so it can perform actions The below command sets the access at the subscription level. ```powershell $Context = Get-AzContext New-AzRoleAssignment -ObjectId -RoleDefinitionName Contributor -Scope "/subscriptions/$($Context.Subscription)" ``` ## Tasks performed by this template This template performs the following tasks * Creates a storage account to store the functions code. * Creates an application insights resource to store logs and metrics for the function. * Creates a functions application with managed identity enabled, and running on a consumption plan. For more information about Azure Functions, see the [Azure Functions Overview](https://azure.microsoft.com/en-us/documentation/articles/functions-overview/). ================================================ FILE: templates/101-functions-managed-identity/azuredeploy.json ================================================ { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "functionAppName": { "type": "string", "defaultValue": "[uniqueString(resourceGroup().id)]", "metadata": { "description": "Specify the name of the function application" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Specify the location for the function application resources" } }, "ApplicationInsightsLocation": { "type": "string", "defaultValue": "West Europe", "allowedValues": [ "East US", "South Central US", "North Europe", "West Europe", "Southeast Asia", "West US 2", "Central India", "Canada Central", "UK South" ], "metadata": { "description": "Specify the region for Application Insights data" } }, "runtimeStack": { "type": "string", "defaultValue": "powershell", "allowedValues": [ "powershell", "dotnet", "node", "java" ], "metadata": { "description": "Pick the language runtime that you want enabled" } }, "timezone": { "type": "string", "defaultValue": "UTC", "allowedValues": [ "Dateline Standard Time", "UTC-11", "Aleutian Standard Time", "Hawaiian Standard Time", "Marquesas Standard Time", "Alaskan Standard Time", "UTC-09", "Pacific Standard Time (Mexico)", "UTC-08", "Pacific Standard Time", "US Mountain Standard Time", "Mountain Standard Time (Mexico)", "Mountain Standard Time", "Central America Standard Time", "Central Standard Time", "Easter Island Standard Time", "Central Standard Time (Mexico)", "Canada Central Standard Time", "SA Pacific Standard Time", "Eastern Standard Time (Mexico)", "Eastern Standard Time", "Haiti Standard Time", "Cuba Standard Time", "US Eastern Standard Time", "Turks And Caicos Standard Time", "Paraguay Standard Time", "Atlantic Standard Time", "Venezuela Standard Time", "Central Brazilian Standard Time", "SA Western Standard Time", "Pacific SA Standard Time", "Newfoundland Standard Time", "Tocantins Standard Time", "E. South America Standard Time", "SA Eastern Standard Time", "Argentina Standard Time", "Greenland Standard Time", "Montevideo Standard Time", "Magallanes Standard Time", "Saint Pierre Standard Time", "Bahia Standard Time", "UTC-02", "Mid-Atlantic Standard Time", "Azores Standard Time", "Cape Verde Standard Time", "UTC", "Morocco Standard Time", "GMT Standard Time", "Greenwich Standard Time", "W. Europe Standard Time", "Central Europe Standard Time", "Romance Standard Time", "Sao Tome Standard Time", "Central European Standard Time", "W. Central Africa Standard Time", "Jordan Standard Time", "GTB Standard Time", "Middle East Standard Time", "Egypt Standard Time", "E. Europe Standard Time", "Syria Standard Time", "West Bank Standard Time", "South Africa Standard Time", "FLE Standard Time", "Israel Standard Time", "Kaliningrad Standard Time", "Sudan Standard Time", "Libya Standard Time", "Namibia Standard Time", "Arabic Standard Time", "Turkey Standard Time", "Arab Standard Time", "Belarus Standard Time", "Russian Standard Time", "E. Africa Standard Time", "Iran Standard Time", "Arabian Standard Time", "Astrakhan Standard Time", "Azerbaijan Standard Time", "Russia Time Zone 3", "Mauritius Standard Time", "Saratov Standard Time", "Georgian Standard Time", "Caucasus Standard Time", "Afghanistan Standard Time", "West Asia Standard Time", "Ekaterinburg Standard Time", "Pakistan Standard Time", "India Standard Time", "Sri Lanka Standard Time", "Nepal Standard Time", "Central Asia Standard Time", "Bangladesh Standard Time", "Omsk Standard Time", "Myanmar Standard Time", "SE Asia Standard Time", "Altai Standard Time", "W. Mongolia Standard Time", "North Asia Standard Time", "N. Central Asia Standard Time", "Tomsk Standard Time", "China Standard Time", "North Asia East Standard Time", "Singapore Standard Time", "W. Australia Standard Time", "Taipei Standard Time", "Ulaanbaatar Standard Time", "Aus Central W. Standard Time", "Transbaikal Standard Time", "Tokyo Standard Time", "North Korea Standard Time", "Korea Standard Time", "Yakutsk Standard Time", "Cen. Australia Standard Time", "AUS Central Standard Time", "E. Australia Standard Time", "AUS Eastern Standard Time", "West Pacific Standard Time", "Tasmania Standard Time", "Vladivostok Standard Time", "Lord Howe Standard Time", "Bougainville Standard Time", "Russia Time Zone 10", "Magadan Standard Time", "Norfolk Standard Time", "Sakhalin Standard Time", "Central Pacific Standard Time", "Russia Time Zone 11", "New Zealand Standard Time", "UTC+12", "Fiji Standard Time", "Kamchatka Standard Time", "Chatham Islands Standard Time", "UTC+13", "Tonga Standard Time", "Samoa Standard Time", "Line Islands Standard Time" ], "metadata": { "description": "Pick the timezone to use for the function" } } }, "variables": { "hostingPlanName": "[parameters('functionAppName')]", "storageAccountName": "[concat('storage', uniquestring(resourceGroup().id))]" }, "resources": [ { "name": "[parameters('functionAppName')]", "type": "Microsoft.Web/sites", "apiVersion": "2018-02-01", "location": "[parameters('location')]", "kind": "functionapp", "dependsOn": [ "[resourceId('Microsoft.Web/serverfarms/', variables('hostingPlanName'))]", "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", "[resourceId('microsoft.insights/components/', parameters('functionAppName'))]" ], "identity": { "type": "SystemAssigned" }, "properties": { "siteConfig": { "appSettings": [ { "name": "FUNCTIONS_WORKER_RUNTIME", "value": "[parameters('runtimeStack')]" }, { "name": "AzureWebJobsStorage", "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2017-06-01').keys[0].value)]" }, { "name": "FUNCTIONS_EXTENSION_VERSION", "value": "~2" }, { "name": "APPINSIGHTS_INSTRUMENTATIONKEY", "value": "[reference(resourceId('microsoft.insights/components/', parameters('functionAppName')), '2018-05-01-preview').InstrumentationKey]" }, { "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2017-06-01').keys[0].value)]" }, { "name": "WEBSITE_CONTENTSHARE", "value": "[toLower(parameters('functionAppName'))]" }, { "name": "WEBSITE_TIME_ZONE", "value": "[parameters('timezone')]" } ] }, "name": "[parameters('functionAppName')]", "clientAffinityEnabled": false, "serverFarmId": "[resourceId('Microsoft.Web/serverfarms/', variables('hostingPlanName'))]" } }, { "type": "Microsoft.Web/serverfarms", "apiVersion": "2018-11-01", "name": "[variables('hostingPlanName')]", "location": "[parameters('location')]", "properties": { "name": "[variables('hostingPlanName')]" }, "sku": { "name": "Y1", "tier": "Dynamic", "size": "Y1", "family": "Y", "capacity": 0 } }, { "apiVersion": "2017-06-01", "type": "Microsoft.Storage/storageAccounts", "name": "[variables('storageAccountName')]", "location": "[parameters('location')]", "sku": { "name": "Standard_LRS" } }, { "apiVersion": "2018-05-01-preview", "name": "[parameters('functionAppName')]", "type": "Microsoft.Insights/components", "location": "[parameters('ApplicationInsightsLocation')]", "tags": { "[concat('hidden-link:', resourceId('Microsoft.Web/sites/', parameters('functionAppName')))]": "Resource" }, "properties": { "ApplicationId": "[parameters('functionAppName')]" } } ], "outputs": { "principalId": { "type": "string", "value": "[reference(concat(resourceId('Microsoft.Web/sites/', parameters('functionAppName')), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId]" } } } ================================================ FILE: templates/101-functions-managed-identity/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "functionAppName": { "value": "GEN-UNIQUE" } } } ================================================ FILE: templates/101-functions-managed-identity/metadata.json ================================================ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", "itemDisplayName": "Creates a function app with managed service identity.", "description": "Creates a function app with managed service identity enabled with Application Insights set up for logs and metrics.", "summary": "Creates a function app with managed service identity.", "githubUsername": "eamonoreilly", "dateUpdated": "2019-02-08" } ================================================ FILE: templates/101-storage-account-create/README.md ================================================ # Create a Standard Storage Account Create a Standard Storage Account - This template creates a Standard Storage account. If you are new to Azure Storage account, see: - [Azure Storage account documentation](http://azure.microsoft.com/documentation/articles/storage-create-storage-account/) - [Azure Storage account template reference](https://docs.microsoft.com/azure/templates/microsoft.storage/allversions) - [Quickstart templates](https://azure.microsoft.com/resources/templates/?resourceType=Microsoft.Storage&pageNumber=1&sort=Popular) If you are new to the template development, see: - [Azure Resource Manager documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/) Tags: Azure Storage account, Resource Manager, Resource Manager templates, ARM templates ================================================ FILE: templates/101-storage-account-create/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "storageAccountType": { "type": "string", "defaultValue": "Standard_LRS", "allowedValues": [ "Standard_LRS", "Standard_GRS", "Standard_ZRS", "Premium_LRS" ], "metadata": { "description": "Storage Account type" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } } }, "variables": { "storageAccountName": "[concat('store', uniquestring(resourceGroup().id))]" }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "name": "[variables('storageAccountName')]", "location": "[parameters('location')]", "apiVersion": "2018-07-01", "sku": { "name": "[parameters('storageAccountType')]" }, "kind": "StorageV2", "properties": {} } ], "outputs": { "storageAccountName": { "type": "string", "value": "[variables('storageAccountName')]" } } } ================================================ FILE: templates/101-storage-account-create/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { } } ================================================ FILE: templates/101-storage-account-create/metadata.json ================================================ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", "itemDisplayName": "Create a Standard Storage Account", "description": "This template creates a Standard Storage Account", "summary": "Create a Standard Storage Account", "githubUsername": "bmoore-msft", "dateUpdated": "2019-02-28" } ================================================ FILE: templates/101-vm-simple-windows/README.md ================================================ # Very simple deployment of a Windows VM This template allows you to deploy a simple Windows VM using a few different options for the Windows version, using the latest patched version. This will deploy a A2 size VM in the resource group location and return the fully qualified domain name of the VM. If you are new to Azure virtual machines, see: - [Azure Virtual Machines](https://azure.microsoft.com/services/virtual-machines/). - [Azure Linux Virtual Machines documentation](https://docs.microsoft.com/azure/virtual-machines/linux/) - [Azure Windows Virtual Machines documentation](https://docs.microsoft.com/azure/virtual-machines/windows/) - [Template reference](https://docs.microsoft.com/azure/templates/microsoft.compute/allversions) - [Quickstart templates](https://azure.microsoft.com/resources/templates/?resourceType=Microsoft.Compute&pageNumber=1&sort=Popular) If you are new to template deployment, see: [Azure Resource Manager documentation](https://docs.microsoft.com/azure/azure-resource-manager/) ================================================ FILE: templates/101-vm-simple-windows/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "type": "string", "metadata": { "description": "Username for the Virtual Machine." } }, "adminPassword": { "type": "securestring", "metadata": { "description": "Password for the Virtual Machine." } }, "dnsLabelPrefix": { "type": "string", "metadata": { "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." } }, "windowsOSVersion": { "type": "string", "defaultValue": "2016-Datacenter", "allowedValues": [ "2008-R2-SP1", "2012-Datacenter", "2012-R2-Datacenter", "2016-Nano-Server", "2016-Datacenter-with-Containers", "2016-Datacenter", "2019-Datacenter" ], "metadata": { "description": "The Windows version for the VM. This will pick a fully patched image of this given Windows version." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } } }, "variables": { "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'sawinvm')]", "nicName": "myVMNic", "addressPrefix": "10.0.0.0/16", "subnetName": "Subnet", "subnetPrefix": "10.0.0.0/24", "publicIPAddressName": "myPublicIP", "vmName": "SimpleWinVM", "virtualNetworkName": "MyVNET", "subnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), variables('subnetName'))]" }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2018-11-01", "name": "[variables('storageAccountName')]", "location": "[parameters('location')]", "sku": { "name": "Standard_LRS" }, "kind": "Storage", "properties": {} }, { "type": "Microsoft.Network/publicIPAddresses", "apiVersion": "2018-11-01", "name": "[variables('publicIPAddressName')]", "location": "[parameters('location')]", "properties": { "publicIPAllocationMethod": "Dynamic", "dnsSettings": { "domainNameLabel": "[parameters('dnsLabelPrefix')]" } } }, { "type": "Microsoft.Network/virtualNetworks", "apiVersion": "2018-11-01", "name": "[variables('virtualNetworkName')]", "location": "[parameters('location')]", "properties": { "addressSpace": { "addressPrefixes": [ "[variables('addressPrefix')]" ] }, "subnets": [ { "name": "[variables('subnetName')]", "properties": { "addressPrefix": "[variables('subnetPrefix')]" } } ] } }, { "type": "Microsoft.Network/networkInterfaces", "apiVersion": "2018-11-01", "name": "[variables('nicName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", "[resourceId('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" ], "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Dynamic", "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]" }, "subnet": { "id": "[variables('subnetRef')]" } } } ] } }, { "type": "Microsoft.Compute/virtualMachines", "apiVersion": "2018-10-01", "name": "[variables('vmName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]", "[resourceId('Microsoft.Network/networkInterfaces/', variables('nicName'))]" ], "properties": { "hardwareProfile": { "vmSize": "Standard_A2" }, "osProfile": { "computerName": "[variables('vmName')]", "adminUsername": "[parameters('adminUsername')]", "adminPassword": "[parameters('adminPassword')]" }, "storageProfile": { "imageReference": { "publisher": "MicrosoftWindowsServer", "offer": "WindowsServer", "sku": "[parameters('windowsOSVersion')]", "version": "latest" }, "osDisk": { "createOption": "FromImage" }, "dataDisks": [ { "diskSizeGB": 1023, "lun": 0, "createOption": "Empty" } ] }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]" } ] }, "diagnosticsProfile": { "bootDiagnostics": { "enabled": true, "storageUri": "[reference(resourceId('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))).primaryEndpoints.blob]" } } } } ], "outputs": { "hostname": { "type": "string", "value": "[reference(variables('publicIPAddressName')).dnsSettings.fqdn]" } } } ================================================ FILE: templates/101-vm-simple-windows/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "value": "GEN-USER" }, "adminPassword": { "value": "GEN-PASSWORD" }, "dnsLabelPrefix": { "value": "GEN-UNIQUE" } } } ================================================ FILE: templates/101-vm-simple-windows/metadata.json ================================================ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", "itemDisplayName": "Deploy a simple Windows VM", "icon": "windowsVM", "description": "This template allows you to deploy a simple Windows VM using a few different options for the Windows version, using the latest patched version. This will deploy a A2 size VM in the resource group location and return the FQDN of the VM.", "summary": "This template takes a minimum amount of parameters and deploys a Windows VM, using the latest patched version.", "githubUsername": "bmoore-msft", "dateUpdated": "2019-03-21" } ================================================ FILE: templates/101-webapp-basic-windows/README.md ================================================ # Deploy a app service plan and a basic Windows web app ## Description This template allows you to deploy an app service plan and a basic Windows web app. ================================================ FILE: templates/101-webapp-basic-windows/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "webAppName": { "type": "string", "metadata": { "description": "Base name of the resource such as web app name and app service plan" }, "minLength": 2 }, "sku":{ "type": "string", "defaultValue" : "S1", "metadata": { "description": "The SKU of App Service Plan, by default is Standard S1" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources" } } }, "variables": { "webAppPortalName": "[concat(parameters('webAppName'), '-webapp')]", "appServicePlanName": "[concat('AppServicePlan-', parameters('webAppName'))]" }, "resources": [ { "apiVersion": "2017-08-01", "type": "Microsoft.Web/serverfarms", "kind": "app", "name": "[variables('appServicePlanName')]", "location": "[parameters('location')]", "properties": {}, "dependsOn": [], "sku": { "name": "[parameters('sku')]" } }, { "apiVersion": "2016-08-01", "type": "Microsoft.Web/sites", "kind": "app", "name": "[variables('webAppPortalName')]", "location": "[parameters('location')]", "properties": { "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]" }, "dependsOn": [ "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]" ] } ] } ================================================ FILE: templates/101-webapp-basic-windows/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "webAppName": { "value": "GEN-UNIQUE" } } } ================================================ FILE: templates/101-webapp-basic-windows/metadata.json ================================================ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", "itemDisplayName": "Deploy a basic Windows web app", "description": "This template allows you to deploy an app service plan and a basic Windows web app", "summary": "This template allows you to deploy an app service plan and a basic Windows web app", "githubUsername": "cloudmelon", "dateUpdated": "2018-07-31" } ================================================ FILE: templates/201-2-vms-loadbalancer-lbrules/README.md ================================================ # Create 2 Virtual Machines under a Load balancer and configures Load Balancing rules for the VMs This template allows you to create 2 Virtual Machines under a Load balancer and configure a load balancing rule on Port 80. This template also deploys a Storage Account, Virtual Network, Public IP address, Availability Set and Network Interfaces. In this template, we use the resource loops capability to create the network interfaces and virtual machines ================================================ FILE: templates/201-2-vms-loadbalancer-lbrules/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", "contentVersion": "1.0.0.0", "parameters": { "storageAccountName": { "type": "string", "metadata": { "description": "Name of storage account" } }, "adminUsername": { "type": "string", "metadata": { "description": "Admin username" } }, "adminPassword": { "type": "securestring", "metadata": { "description": "Admin password" } }, "dnsNameforLBIP": { "type": "string", "metadata": { "description": "DNS for Load Balancer IP" } }, "vmNamePrefix": { "type": "string", "defaultValue": "myVM", "metadata": { "description": "Prefix to use for VM names" } }, "imagePublisher": { "type": "string", "defaultValue": "MicrosoftWindowsServer", "metadata": { "description": "Image Publisher" } }, "imageOffer": { "type": "string", "defaultValue": "WindowsServer", "metadata": { "description": "Image Offer" } }, "imageSKU": { "type": "string", "defaultValue": "2012-R2-Datacenter", "metadata": { "description": "Image SKU" } }, "lbName": { "type": "string", "defaultValue": "myLB", "metadata": { "description": "Load Balancer name" } }, "nicNamePrefix": { "type": "string", "defaultValue": "nic", "metadata": { "description": "Network Interface name prefix" } }, "publicIPAddressName": { "type": "string", "defaultValue": "myPublicIP", "metadata": { "description": "Public IP Name" } }, "vnetName": { "type": "string", "defaultValue": "myVNET", "metadata": { "description": "VNET name" } }, "vmSize": { "type": "string", "defaultValue": "Standard_D1", "metadata": { "description": "Size of the VM" } } }, "variables": { "storageAccountType": "Standard_LRS", "availabilitySetName": "myAvSet", "addressPrefix": "10.0.0.0/16", "subnetName": "Subnet-1", "subnetPrefix": "10.0.0.0/24", "publicIPAddressType": "Dynamic", "subnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), variables ('subnetName'))]", "publicIPAddressID": "[resourceId('Microsoft.Network/publicIPAddresses',parameters('publicIPAddressName'))]", "numberOfInstances": 2, "lbID": "[resourceId('Microsoft.Network/loadBalancers',parameters('lbName'))]", "frontEndIPConfigID": "[concat(variables('lbID'),'/frontendIPConfigurations/LoadBalancerFrontEnd')]", "lbPoolID": "[concat(variables('lbID'),'/backendAddressPools/BackendPool1')]", "lbProbeID": "[concat(variables('lbID'),'/probes/tcpProbe')]" }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "name": "[parameters('storageAccountName')]", "apiVersion": "2015-05-01-preview", "location": "[resourceGroup().location]", "properties": { "accountType": "[variables('storageAccountType')]" } }, { "type": "Microsoft.Compute/availabilitySets", "name": "[variables('availabilitySetName')]", "apiVersion": "2016-04-30-preview", "location": "[resourceGroup().location]", "properties": { "platformFaultDomainCount": 2, "platformUpdateDomainCount": 2, "managed": true } }, { "apiVersion": "2015-05-01-preview", "type": "Microsoft.Network/publicIPAddresses", "name": "[parameters('publicIPAddressName')]", "location": "[resourceGroup().location]", "properties": { "publicIPAllocationMethod": "[variables('publicIPAddressType')]", "dnsSettings": { "domainNameLabel": "[parameters('dnsNameforLBIP')]" } } }, { "apiVersion": "2015-05-01-preview", "type": "Microsoft.Network/virtualNetworks", "name": "[parameters('vnetName')]", "location": "[resourceGroup().location]", "properties": { "addressSpace": { "addressPrefixes": [ "[variables('addressPrefix')]" ] }, "subnets": [ { "name": "[variables('subnetName')]", "properties": { "addressPrefix": "[variables('subnetPrefix')]" } } ] } }, { "apiVersion": "2015-05-01-preview", "type": "Microsoft.Network/networkInterfaces", "name": "[concat(parameters('nicNamePrefix'), copyindex())]", "location": "[resourceGroup().location]", "copy": { "name": "nicLoop", "count": "[variables('numberOfInstances')]" }, "dependsOn": [ "[concat('Microsoft.Network/virtualNetworks/', parameters('vnetName'))]", "[concat('Microsoft.Network/loadBalancers/', parameters('lbName'))]" ], "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Dynamic", "subnet": { "id": "[variables('subnetRef')]" }, "loadBalancerBackendAddressPools": [ { "id": "[concat(variables('lbID'), '/backendAddressPools/BackendPool1')]" } ], "loadBalancerInboundNatRules": [ { "id": "[concat(variables('lbID'),'/inboundNatRules/RDP-VM', copyindex())]" } ] } } ] } }, { "apiVersion": "2015-05-01-preview", "name": "[parameters('lbName')]", "type": "Microsoft.Network/loadBalancers", "location": "[resourceGroup().location]", "dependsOn": [ "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]" ], "properties": { "frontendIPConfigurations": [ { "name": "LoadBalancerFrontEnd", "properties": { "publicIPAddress": { "id": "[variables('publicIPAddressID')]" } } } ], "backendAddressPools": [ { "name": "BackendPool1" } ], "inboundNatRules": [ { "name": "RDP-VM0", "properties": { "frontendIPConfiguration": { "id": "[variables('frontEndIPConfigID')]" }, "protocol": "Tcp", "frontendPort": 50001, "backendPort": 3389, "enableFloatingIP": false } }, { "name": "RDP-VM1", "properties": { "frontendIPConfiguration": { "id": "[variables('frontEndIPConfigID')]" }, "protocol": "Tcp", "frontendPort": 50002, "backendPort": 3389, "enableFloatingIP": false } } ], "loadBalancingRules": [ { "name": "LBRule", "properties": { "frontendIPConfiguration": { "id": "[variables('frontEndIPConfigID')]" }, "backendAddressPool": { "id": "[variables('lbPoolID')]" }, "protocol": "Tcp", "frontendPort": 80, "backendPort": 80, "enableFloatingIP": false, "idleTimeoutInMinutes": 5, "probe": { "id": "[variables('lbProbeID')]" } } } ], "probes": [ { "name": "tcpProbe", "properties": { "protocol": "Tcp", "port": 80, "intervalInSeconds": 5, "numberOfProbes": 2 } } ] } }, { "apiVersion": "2016-04-30-preview", "type": "Microsoft.Compute/virtualMachines", "name": "[concat(parameters('vmNamePrefix'), copyindex())]", "copy": { "name": "virtualMachineLoop", "count": "[variables('numberOfInstances')]" }, "location": "[resourceGroup().location]", "dependsOn": [ "[concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]", "[concat('Microsoft.Network/networkInterfaces/', parameters('nicNamePrefix'), copyindex())]", "[concat('Microsoft.Compute/availabilitySets/', variables('availabilitySetName'))]" ], "properties": { "availabilitySet": { "id": "[resourceId('Microsoft.Compute/availabilitySets',variables('availabilitySetName'))]" }, "hardwareProfile": { "vmSize": "[parameters('vmSize')]" }, "osProfile": { "computerName": "[concat(parameters('vmNamePrefix'), copyIndex())]", "adminUsername": "[parameters('adminUsername')]", "adminPassword": "[parameters('adminPassword')]" }, "storageProfile": { "imageReference": { "publisher": "[parameters('imagePublisher')]", "offer": "[parameters('imageOffer')]", "sku": "[parameters('imageSKU')]", "version": "latest" }, "osDisk": { "createOption": "FromImage" } }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(parameters('nicNamePrefix'),copyindex()))]" } ] }, "diagnosticsProfile": { "bootDiagnostics": { "enabled": true, "storageUri": "[concat('http://',parameters('storageAccountName'),'.blob.core.windows.net')]" } } } } ] } ================================================ FILE: templates/201-2-vms-loadbalancer-lbrules/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "storageAccountName": { "value": "GEN-UNIQUE" }, "adminUsername": { "value": "admin123" }, "adminPassword": { "value": "Admin123_!" }, "dnsNameforLBIP": { "value": "GEN-UNIQUE" } } } ================================================ FILE: templates/201-2-vms-loadbalancer-lbrules/metadata.json ================================================ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", "itemDisplayName": "2 VMs in a Load Balancer and load balancing rules", "description": "This template allows you to create 2 Virtual Machines under a Load balancer and configure a load balancing rule on Port 80. This template also deploys a Storage Account, Virtual Network, Public IP address, Availability Set and Network Interfaces. In this template, we use the resource loops capability to create the network interfaces and virtual machines", "summary": "2 VMs in a Load Balancer and Load Balancer rules", "githubUsername": "ypitsch", "dateUpdated": "2015-04-28" } ================================================ FILE: templates/201-sql-auditing-server-policy-to-blob-storage/README.md ================================================ # Deploy an Azure SQL Server with Auditing enabled to write audit logs to Azure blob storage account This template allows you to deploy an Azure SQL server with Aduiting enabled to write audit logs to a blob storage Auditing for Azure SQL Database and SQL Data Warehouse tracks database events and writes them to an audit log in your Azure storage account, OMS workspace or Event Hubs. For more information on SQL database auditing , see the [official documentation]( https://docs.microsoft.com/en-us/azure/sql-database/sql-database-auditing). ================================================ FILE: templates/201-sql-auditing-server-policy-to-blob-storage/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "sqlServerName": { "type": "string", "defaultValue": "[concat('server-', uniqueString(resourceGroup().id, deployment().name))]", "metadata": { "description": "Name of the SQL server" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } }, "sqlAdministratorLogin": { "type": "string", "metadata": { "description": "The administrator username of the SQL Server." } }, "sqlAdministratorLoginPassword": { "type": "securestring", "metadata": { "description": "The administrator password of the SQL Server." } }, "storageAccountName": { "type": "string", "defaultValue": "[concat('sqlaudit',uniqueString(resourceGroup().id))]", "metadata": { "description": "The name of the auditing storage account." } } }, "variables": {}, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "name": "[parameters('storageAccountName')]", "apiVersion": "2017-10-01", "location": "[parameters('location')]", "sku": { "name": "Standard_LRS" }, "kind": "Storage", "properties": {} }, { "type": "Microsoft.Sql/servers", "apiVersion": "2015-05-01-preview", "location": "[parameters('location')]", "name": "[parameters('sqlServerName')]", "properties": { "administratorLogin": "[parameters('sqlAdministratorLogin')]", "administratorLoginPassword": "[parameters('sqlAdministratorLoginPassword')]", "version": "12.0" }, "tags": { "DisplayName": "[parameters('sqlServerName')]" }, "resources": [ { "apiVersion": "2017-03-01-preview", "type": "auditingSettings", "name": "DefaultAuditingSettings", "dependsOn": [ "[parameters('sqlServerName')]", "[parameters('storageAccountName')]" ], "properties": { "state": "Enabled", "storageEndpoint": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2018-03-01-preview').PrimaryEndpoints.Blob]", "storageAccountAccessKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2018-03-01-preview').keys[0].value]", "storageAccountSubscriptionId": "[subscription().subscriptionId]", "auditActionsAndGroups": null, "isStorageSecondaryKeyInUse": false } } ] } ] } ================================================ FILE: templates/201-sql-auditing-server-policy-to-blob-storage/azuredeploy.parameters.json ================================================ { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "sqlAdministratorLogin": { "value": "GEN-UNIQUE" }, "sqlAdministratorLoginPassword": { "value": "GEN-PASSWORD" } } } ================================================ FILE: templates/201-sql-auditing-server-policy-to-blob-storage/metadata.json ================================================ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", "itemDisplayName": "Azure SQL Server with Auditing written to a blob storage", "description": "This template allows you to deploy an Azure SQL server with Auditing enabled to write audit logs to a blob storage", "summary": "Deploy an Azure SQL Server with Auditing enabled to write audit logs to a blob storage", "githubUsername": "lubalibu", "dateUpdated": "2018-11-18" } ================================================ FILE: templates/AZ-300/AKS/AKS.deployproj ================================================  Debug AnyCPU Release AnyCPU 5316c7a1-f97f-4389-8c0f-78029a1ddb43 False ================================================ FILE: templates/AZ-300/AKS/Deploy-AzureResourceGroup.ps1 ================================================ #Requires -Version 3.0 Param( [string] [Parameter(Mandatory=$true)] $ResourceGroupLocation, [string] $ResourceGroupName = 'AZ-300', [switch] $UploadArtifacts, [string] $StorageAccountName, [string] $StorageContainerName = $ResourceGroupName.ToLowerInvariant() + '-stageartifacts', [string] $TemplateFile = 'azuredeploy.json', [string] $TemplateParametersFile = 'azuredeploy.parameters.json', [string] $ArtifactStagingDirectory = '.', [string] $DSCSourceFolder = 'DSC', [switch] $ValidateOnly ) try { [Microsoft.Azure.Common.Authentication.AzureSession]::ClientFactory.AddUserAgent("VSAzureTools-$UI$($host.name)".replace(' ','_'), '3.0.0') } catch { } $ErrorActionPreference = 'Stop' Set-StrictMode -Version 3 function Format-ValidationOutput { param ($ValidationOutput, [int] $Depth = 0) Set-StrictMode -Off return @($ValidationOutput | Where-Object { $_ -ne $null } | ForEach-Object { @(' ' * $Depth + ': ' + $_.Message) + @(Format-ValidationOutput @($_.Details) ($Depth + 1)) }) } $OptionalParameters = New-Object -TypeName Hashtable $TemplateFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateFile)) $TemplateParametersFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateParametersFile)) if ($UploadArtifacts) { # Convert relative paths to absolute paths if needed $ArtifactStagingDirectory = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $ArtifactStagingDirectory)) $DSCSourceFolder = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $DSCSourceFolder)) # Parse the parameter file and update the values of artifacts location and artifacts location SAS token if they are present $JsonParameters = Get-Content $TemplateParametersFile -Raw | ConvertFrom-Json if (($JsonParameters | Get-Member -Type NoteProperty 'parameters') -ne $null) { $JsonParameters = $JsonParameters.parameters } $ArtifactsLocationName = '_artifactsLocation' $ArtifactsLocationSasTokenName = '_artifactsLocationSasToken' $OptionalParameters[$ArtifactsLocationName] = $JsonParameters | Select -Expand $ArtifactsLocationName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore $OptionalParameters[$ArtifactsLocationSasTokenName] = $JsonParameters | Select -Expand $ArtifactsLocationSasTokenName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore # Create DSC configuration archive if (Test-Path $DSCSourceFolder) { $DSCSourceFilePaths = @(Get-ChildItem $DSCSourceFolder -File -Filter '*.ps1' | ForEach-Object -Process {$_.FullName}) foreach ($DSCSourceFilePath in $DSCSourceFilePaths) { $DSCArchiveFilePath = $DSCSourceFilePath.Substring(0, $DSCSourceFilePath.Length - 4) + '.zip' Publish-AzureRmVMDscConfiguration $DSCSourceFilePath -OutputArchivePath $DSCArchiveFilePath -Force -Verbose } } # Create a storage account name if none was provided if ($StorageAccountName -eq '') { $StorageAccountName = 'stage' + ((Get-AzureRmContext).Subscription.SubscriptionId).Replace('-', '').substring(0, 19) } $StorageAccount = (Get-AzureRmStorageAccount | Where-Object{$_.StorageAccountName -eq $StorageAccountName}) # Create the storage account if it doesn't already exist if ($StorageAccount -eq $null) { $StorageResourceGroupName = 'ARM_Deploy_Staging' New-AzureRmResourceGroup -Location "$ResourceGroupLocation" -Name $StorageResourceGroupName -Force $StorageAccount = New-AzureRmStorageAccount -StorageAccountName $StorageAccountName -Type 'Standard_LRS' -ResourceGroupName $StorageResourceGroupName -Location "$ResourceGroupLocation" } # Generate the value for artifacts location if it is not provided in the parameter file if ($OptionalParameters[$ArtifactsLocationName] -eq $null) { $OptionalParameters[$ArtifactsLocationName] = $StorageAccount.Context.BlobEndPoint + $StorageContainerName } # Copy files from the local storage staging location to the storage account container New-AzureStorageContainer -Name $StorageContainerName -Context $StorageAccount.Context -ErrorAction SilentlyContinue *>&1 $ArtifactFilePaths = Get-ChildItem $ArtifactStagingDirectory -Recurse -File | ForEach-Object -Process {$_.FullName} foreach ($SourcePath in $ArtifactFilePaths) { Set-AzureStorageBlobContent -File $SourcePath -Blob $SourcePath.Substring($ArtifactStagingDirectory.length + 1) ` -Container $StorageContainerName -Context $StorageAccount.Context -Force } # Generate a 4 hour SAS token for the artifacts location if one was not provided in the parameters file if ($OptionalParameters[$ArtifactsLocationSasTokenName] -eq $null) { $OptionalParameters[$ArtifactsLocationSasTokenName] = ConvertTo-SecureString -AsPlainText -Force ` (New-AzureStorageContainerSASToken -Container $StorageContainerName -Context $StorageAccount.Context -Permission r -ExpiryTime (Get-Date).AddHours(4)) } } # Create the resource group only when it doesn't already exist if ((Get-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -ErrorAction SilentlyContinue) -eq $null) { New-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -Force -ErrorAction Stop } if ($ValidateOnly) { $ErrorMessages = Format-ValidationOutput (Test-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName ` -TemplateFile $TemplateFile ` -TemplateParameterFile $TemplateParametersFile ` @OptionalParameters) if ($ErrorMessages) { Write-Output '', 'Validation returned the following errors:', @($ErrorMessages), '', 'Template is invalid.' } else { Write-Output '', 'Template is valid.' } } else { New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $TemplateFile).BaseName + '-' + ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm')) ` -ResourceGroupName $ResourceGroupName ` -TemplateFile $TemplateFile ` -TemplateParameterFile $TemplateParametersFile ` @OptionalParameters ` -Force -Verbose ` -ErrorVariable ErrorMessages if ($ErrorMessages) { Write-Output '', 'Template deployment returned the following errors:', @(@($ErrorMessages) | ForEach-Object { $_.Exception.Message.TrimEnd("`r`n") }) } } ================================================ FILE: templates/AZ-300/AKS/Deployment.targets ================================================ Debug AnyCPU bin\$(Configuration)\ false true false None obj\ $(BaseIntermediateOutputPath)\ $(BaseIntermediateOutputPath)$(Configuration)\ $(IntermediateOutputPath)ProjectReferences $(ProjectReferencesOutputPath)\ true false false Always Never false Build _GetDeploymentProjectContent; _CalculateContentOutputRelativePaths; _GetReferencedProjectsOutput; _CalculateArtifactStagingDirectory; _CopyOutputToArtifactStagingDirectory; Configuration=$(Configuration);Platform=$(Platform) $([System.IO.Path]::GetFileNameWithoutExtension('%(ProjectReference.Identity)')) $(OutDir) $(OutputPath) $(ArtifactStagingDirectory)\ $(ArtifactStagingDirectory)staging\ $(Build_StagingDirectory) <_OriginalIdentity>%(DeploymentProjectContentOutput.Identity) <_RelativePath>$(_OriginalIdentity.Replace('$(MSBuildProjectDirectory)', '')) $(_RelativePath) PrepareForRun ================================================ FILE: templates/AZ-300/AKS/README.md ================================================ # Azure Container Service (AKS)             This template deploys an **AKS cluster**. See https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough for a walkthrough. To use keys stored in keyvault, replace ```"value":""``` with a reference to keyvault in parameters file. For example: ```json "servicePrincipalClientSecret": { "reference": { "keyVault": { "id": "" }, "secretName": "" } } ``` ================================================ FILE: templates/AZ-300/AKS/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.1", "parameters": { "clusterName": { "type": "string", "defaultValue":"aks101cluster", "metadata": { "description": "The name of the Managed Cluster resource." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "The location of the Managed Cluster resource." } }, "dnsPrefix": { "type": "string", "metadata": { "description": "Optional DNS prefix to use with hosted Kubernetes API server FQDN." } }, "osDiskSizeGB": { "type": "int", "defaultValue": 0, "metadata": { "description": "Disk size (in GB) to provision for each of the agent pool nodes. This value ranges from 0 to 1023. Specifying 0 will apply the default disk size for that agentVMSize." }, "minValue": 0, "maxValue": 1023 }, "agentCount": { "type": "int", "defaultValue": 3, "metadata": { "description": "The number of nodes for the cluster." }, "minValue": 1, "maxValue": 50 }, "agentVMSize": { "type": "string", "defaultValue": "Standard_DS2_v2", "metadata": { "description": "The size of the Virtual Machine." } }, "linuxAdminUsername": { "type": "string", "metadata": { "description": "User name for the Linux Virtual Machines." } }, "sshRSAPublicKey": { "type": "string", "metadata": { "description": "Configure all linux machines with the SSH RSA public key string. Your key should include three parts, for example 'ssh-rsa AAAAB...snip...UcyupgH azureuser@linuxvm'" } }, "servicePrincipalClientId": { "metadata": { "description": "Client ID (used by cloudprovider)" }, "type": "securestring" }, "servicePrincipalClientSecret": { "metadata": { "description": "The Service Principal Client Secret." }, "type": "securestring" }, "osType": { "type": "string", "defaultValue": "Linux", "allowedValues": [ "Linux" ], "metadata": { "description": "The type of operating system." } } }, "resources": [ { "apiVersion": "2018-03-31", "type": "Microsoft.ContainerService/managedClusters", "location": "[parameters('location')]", "name": "[parameters('clusterName')]", "properties": { "dnsPrefix": "[parameters('dnsPrefix')]", "agentPoolProfiles": [ { "name": "agentpool", "osDiskSizeGB": "[parameters('osDiskSizeGB')]", "count": "[parameters('agentCount')]", "vmSize": "[parameters('agentVMSize')]", "osType": "[parameters('osType')]", "storageProfile": "ManagedDisks" } ], "linuxProfile": { "adminUsername": "[parameters('linuxAdminUsername')]", "ssh": { "publicKeys": [ { "keyData": "[parameters('sshRSAPublicKey')]" } ] } }, "servicePrincipalProfile": { "clientId": "[parameters('servicePrincipalClientId')]", "Secret": "[parameters('servicePrincipalClientSecret')]" } } } ], "outputs": { "controlPlaneFQDN": { "type": "string", "value": "[reference(parameters('clusterName')).fqdn]" } } } ================================================ FILE: templates/AZ-300/AKS/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.1", "parameters": { "dnsPrefix": { "value": null }, "linuxAdminUsername": { "value": null }, "sshRSAPublicKey": { "value": null } } } ================================================ FILE: templates/AZ-300/AZ-300.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29230.47 MinimumVisualStudioVersion = 10.0.40219.1 Project("{151D2E53-A2C4-4D7D-83FE-D05416EBD58E}") = "VM Copy Loops", "VM Copy Loops.deployproj", "{D668F964-6F42-4175-8457-4EA99FB2E61F}" EndProject Project("{151D2E53-A2C4-4D7D-83FE-D05416EBD58E}") = "S2S-VPN", "bin\S2S-VPN\S2S-VPN.deployproj", "{117C49F7-6397-4A75-8DBB-37ED1E1ED3AD}" EndProject Project("{151D2E53-A2C4-4D7D-83FE-D05416EBD58E}") = "App-Gateway", "App-Gateway\App-Gateway.deployproj", "{7B19F27C-58A4-4670-82CA-6D86109559FD}" EndProject Project("{151D2E53-A2C4-4D7D-83FE-D05416EBD58E}") = "AKS", "AKS\AKS.deployproj", "{5316C7A1-F97F-4389-8C0F-78029A1DDB43}" EndProject Project("{151D2E53-A2C4-4D7D-83FE-D05416EBD58E}") = "WebApp+SQL", "WebApp+SQL\WebApp+SQL.deployproj", "{8CD8C986-6352-439E-B8F2-96E0B6882933}" EndProject Project("{151D2E53-A2C4-4D7D-83FE-D05416EBD58E}") = "KeyVault", "KeyVault\KeyVault.deployproj", "{043153B4-7C7D-4BCF-8B43-56782D6A3824}" EndProject Project("{151D2E53-A2C4-4D7D-83FE-D05416EBD58E}") = "AppService+Container", "AppService+Container\AppService+Container.deployproj", "{719C3044-FE01-45F1-9134-BF13BD4BEDF3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D668F964-6F42-4175-8457-4EA99FB2E61F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D668F964-6F42-4175-8457-4EA99FB2E61F}.Debug|Any CPU.Build.0 = Debug|Any CPU {D668F964-6F42-4175-8457-4EA99FB2E61F}.Release|Any CPU.ActiveCfg = Release|Any CPU {D668F964-6F42-4175-8457-4EA99FB2E61F}.Release|Any CPU.Build.0 = Release|Any CPU {117C49F7-6397-4A75-8DBB-37ED1E1ED3AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {117C49F7-6397-4A75-8DBB-37ED1E1ED3AD}.Debug|Any CPU.Build.0 = Debug|Any CPU {117C49F7-6397-4A75-8DBB-37ED1E1ED3AD}.Release|Any CPU.ActiveCfg = Release|Any CPU {117C49F7-6397-4A75-8DBB-37ED1E1ED3AD}.Release|Any CPU.Build.0 = Release|Any CPU {7B19F27C-58A4-4670-82CA-6D86109559FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7B19F27C-58A4-4670-82CA-6D86109559FD}.Debug|Any CPU.Build.0 = Debug|Any CPU {7B19F27C-58A4-4670-82CA-6D86109559FD}.Release|Any CPU.ActiveCfg = Release|Any CPU {7B19F27C-58A4-4670-82CA-6D86109559FD}.Release|Any CPU.Build.0 = Release|Any CPU {5316C7A1-F97F-4389-8C0F-78029A1DDB43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5316C7A1-F97F-4389-8C0F-78029A1DDB43}.Debug|Any CPU.Build.0 = Debug|Any CPU {5316C7A1-F97F-4389-8C0F-78029A1DDB43}.Release|Any CPU.ActiveCfg = Release|Any CPU {5316C7A1-F97F-4389-8C0F-78029A1DDB43}.Release|Any CPU.Build.0 = Release|Any CPU {8CD8C986-6352-439E-B8F2-96E0B6882933}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8CD8C986-6352-439E-B8F2-96E0B6882933}.Debug|Any CPU.Build.0 = Debug|Any CPU {8CD8C986-6352-439E-B8F2-96E0B6882933}.Release|Any CPU.ActiveCfg = Release|Any CPU {8CD8C986-6352-439E-B8F2-96E0B6882933}.Release|Any CPU.Build.0 = Release|Any CPU {043153B4-7C7D-4BCF-8B43-56782D6A3824}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {043153B4-7C7D-4BCF-8B43-56782D6A3824}.Debug|Any CPU.Build.0 = Debug|Any CPU {043153B4-7C7D-4BCF-8B43-56782D6A3824}.Release|Any CPU.ActiveCfg = Release|Any CPU {043153B4-7C7D-4BCF-8B43-56782D6A3824}.Release|Any CPU.Build.0 = Release|Any CPU {719C3044-FE01-45F1-9134-BF13BD4BEDF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {719C3044-FE01-45F1-9134-BF13BD4BEDF3}.Debug|Any CPU.Build.0 = Debug|Any CPU {719C3044-FE01-45F1-9134-BF13BD4BEDF3}.Release|Any CPU.ActiveCfg = Release|Any CPU {719C3044-FE01-45F1-9134-BF13BD4BEDF3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A6F06312-9D4B-4AAA-A643-45DFFE7E1FB5} EndGlobalSection EndGlobal ================================================ FILE: templates/AZ-300/App-Gateway/App-Gateway.deployproj ================================================  Debug AnyCPU Release AnyCPU 7b19f27c-58a4-4670-82ca-6d86109559fd False ================================================ FILE: templates/AZ-300/App-Gateway/Deploy-AzureResourceGroup.ps1 ================================================ #Requires -Version 3.0 Param( [string] [Parameter(Mandatory=$true)] $ResourceGroupLocation, [string] $ResourceGroupName = 'AZ-300', [switch] $UploadArtifacts, [string] $StorageAccountName, [string] $StorageContainerName = $ResourceGroupName.ToLowerInvariant() + '-stageartifacts', [string] $TemplateFile = 'azuredeploy.json', [string] $TemplateParametersFile = 'azuredeploy.parameters.json', [string] $ArtifactStagingDirectory = '.', [string] $DSCSourceFolder = 'DSC', [switch] $ValidateOnly ) try { [Microsoft.Azure.Common.Authentication.AzureSession]::ClientFactory.AddUserAgent("VSAzureTools-$UI$($host.name)".replace(' ','_'), '3.0.0') } catch { } $ErrorActionPreference = 'Stop' Set-StrictMode -Version 3 function Format-ValidationOutput { param ($ValidationOutput, [int] $Depth = 0) Set-StrictMode -Off return @($ValidationOutput | Where-Object { $_ -ne $null } | ForEach-Object { @(' ' * $Depth + ': ' + $_.Message) + @(Format-ValidationOutput @($_.Details) ($Depth + 1)) }) } $OptionalParameters = New-Object -TypeName Hashtable $TemplateFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateFile)) $TemplateParametersFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateParametersFile)) if ($UploadArtifacts) { # Convert relative paths to absolute paths if needed $ArtifactStagingDirectory = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $ArtifactStagingDirectory)) $DSCSourceFolder = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $DSCSourceFolder)) # Parse the parameter file and update the values of artifacts location and artifacts location SAS token if they are present $JsonParameters = Get-Content $TemplateParametersFile -Raw | ConvertFrom-Json if (($JsonParameters | Get-Member -Type NoteProperty 'parameters') -ne $null) { $JsonParameters = $JsonParameters.parameters } $ArtifactsLocationName = '_artifactsLocation' $ArtifactsLocationSasTokenName = '_artifactsLocationSasToken' $OptionalParameters[$ArtifactsLocationName] = $JsonParameters | Select -Expand $ArtifactsLocationName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore $OptionalParameters[$ArtifactsLocationSasTokenName] = $JsonParameters | Select -Expand $ArtifactsLocationSasTokenName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore # Create DSC configuration archive if (Test-Path $DSCSourceFolder) { $DSCSourceFilePaths = @(Get-ChildItem $DSCSourceFolder -File -Filter '*.ps1' | ForEach-Object -Process {$_.FullName}) foreach ($DSCSourceFilePath in $DSCSourceFilePaths) { $DSCArchiveFilePath = $DSCSourceFilePath.Substring(0, $DSCSourceFilePath.Length - 4) + '.zip' Publish-AzureRmVMDscConfiguration $DSCSourceFilePath -OutputArchivePath $DSCArchiveFilePath -Force -Verbose } } # Create a storage account name if none was provided if ($StorageAccountName -eq '') { $StorageAccountName = 'stage' + ((Get-AzureRmContext).Subscription.SubscriptionId).Replace('-', '').substring(0, 19) } $StorageAccount = (Get-AzureRmStorageAccount | Where-Object{$_.StorageAccountName -eq $StorageAccountName}) # Create the storage account if it doesn't already exist if ($StorageAccount -eq $null) { $StorageResourceGroupName = 'ARM_Deploy_Staging' New-AzureRmResourceGroup -Location "$ResourceGroupLocation" -Name $StorageResourceGroupName -Force $StorageAccount = New-AzureRmStorageAccount -StorageAccountName $StorageAccountName -Type 'Standard_LRS' -ResourceGroupName $StorageResourceGroupName -Location "$ResourceGroupLocation" } # Generate the value for artifacts location if it is not provided in the parameter file if ($OptionalParameters[$ArtifactsLocationName] -eq $null) { $OptionalParameters[$ArtifactsLocationName] = $StorageAccount.Context.BlobEndPoint + $StorageContainerName } # Copy files from the local storage staging location to the storage account container New-AzureStorageContainer -Name $StorageContainerName -Context $StorageAccount.Context -ErrorAction SilentlyContinue *>&1 $ArtifactFilePaths = Get-ChildItem $ArtifactStagingDirectory -Recurse -File | ForEach-Object -Process {$_.FullName} foreach ($SourcePath in $ArtifactFilePaths) { Set-AzureStorageBlobContent -File $SourcePath -Blob $SourcePath.Substring($ArtifactStagingDirectory.length + 1) ` -Container $StorageContainerName -Context $StorageAccount.Context -Force } # Generate a 4 hour SAS token for the artifacts location if one was not provided in the parameters file if ($OptionalParameters[$ArtifactsLocationSasTokenName] -eq $null) { $OptionalParameters[$ArtifactsLocationSasTokenName] = ConvertTo-SecureString -AsPlainText -Force ` (New-AzureStorageContainerSASToken -Container $StorageContainerName -Context $StorageAccount.Context -Permission r -ExpiryTime (Get-Date).AddHours(4)) } } # Create the resource group only when it doesn't already exist if ((Get-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -ErrorAction SilentlyContinue) -eq $null) { New-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -Force -ErrorAction Stop } if ($ValidateOnly) { $ErrorMessages = Format-ValidationOutput (Test-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName ` -TemplateFile $TemplateFile ` -TemplateParameterFile $TemplateParametersFile ` @OptionalParameters) if ($ErrorMessages) { Write-Output '', 'Validation returned the following errors:', @($ErrorMessages), '', 'Template is invalid.' } else { Write-Output '', 'Template is valid.' } } else { New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $TemplateFile).BaseName + '-' + ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm')) ` -ResourceGroupName $ResourceGroupName ` -TemplateFile $TemplateFile ` -TemplateParameterFile $TemplateParametersFile ` @OptionalParameters ` -Force -Verbose ` -ErrorVariable ErrorMessages if ($ErrorMessages) { Write-Output '', 'Template deployment returned the following errors:', @(@($ErrorMessages) | ForEach-Object { $_.Exception.Message.TrimEnd("`r`n") }) } } ================================================ FILE: templates/AZ-300/App-Gateway/Deployment.targets ================================================ Debug AnyCPU bin\$(Configuration)\ false true false None obj\ $(BaseIntermediateOutputPath)\ $(BaseIntermediateOutputPath)$(Configuration)\ $(IntermediateOutputPath)ProjectReferences $(ProjectReferencesOutputPath)\ true false false Always Never false Build _GetDeploymentProjectContent; _CalculateContentOutputRelativePaths; _GetReferencedProjectsOutput; _CalculateArtifactStagingDirectory; _CopyOutputToArtifactStagingDirectory; Configuration=$(Configuration);Platform=$(Platform) $([System.IO.Path]::GetFileNameWithoutExtension('%(ProjectReference.Identity)')) $(OutDir) $(OutputPath) $(ArtifactStagingDirectory)\ $(ArtifactStagingDirectory)staging\ $(Build_StagingDirectory) <_OriginalIdentity>%(DeploymentProjectContentOutput.Identity) <_RelativePath>$(_OriginalIdentity.Replace('$(MSBuildProjectDirectory)', '')) $(_RelativePath) PrepareForRun ================================================ FILE: templates/AZ-300/App-Gateway/README.md ================================================ # Create an Application Gateway v2 with a Web Application Firewall (WAF) v2             This template is used by the [Azure Application Gateway documentation](https://docs.microsoft.com/azure/application-gateway/) to deploy an Application Gateway v2 with the Web Application Firewall (WAF) v2. ================================================ FILE: templates/AZ-300/App-Gateway/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "applicationGatewayName": { "type": "string", "defaultValue": "applicationGatewayv2", "metadata": { "description": "Application Gateway name" } }, "addressPrefix": { "type": "string", "defaultValue": "10.0.0.0/16", "metadata": { "description": "Address prefix for the virtual network" } }, "subnetPrefix": { "type": "string", "defaultValue": "10.0.0.0/28", "metadata": { "description": "App gateway subnet prefix" } }, "subnet2Prefix": { "type": "string", "defaultValue": "10.0.1.0/28", "metadata": { "description": "Workload subnet prefix" } }, "applicationGatewaySize": { "type": "string", "allowedValues": [ "WAF_v2" ], "defaultValue": "WAF_v2", "metadata": { "description": "Application gateway size" } }, "applicationGatewayTier": { "type": "string", "allowedValues": [ "WAF_v2" ], "defaultValue": "WAF_v2", "metadata": { "description": "Application gateway tier" } }, "capacity": { "type": "int", "allowedValues": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], "defaultValue": 2, "metadata": { "description": "Number of instances" } }, "backendIpAddress1": { "type": "string", "defaultValue": "10.0.1.4", "metadata": { "description": "IP Address for backend server 1" } }, "backendIpAddress2": { "type": "string", "defaultValue": "10.0.1.5", "metadata": { "description": "IP Address for backend server 2" } }, "wafEnabled": { "type": "bool", "defaultValue": true, "metadata": { "description": "WAF Enabled" } }, "wafMode": { "type": "string", "allowedValues": [ "Detection", "Prevention" ], "defaultValue": "Detection", "metadata": { "description": "WAF Mode" } }, "wafRuleSetType": { "type": "string", "allowedValues": [ "OWASP" ], "defaultValue": "OWASP", "metadata": { "description": "WAF Rule Set Type" } }, "wafRuleSetVersion": { "type": "string", "allowedValues": [ "2.2.9", "3.0", "3.1" ], "defaultValue": "3.1", "metadata": { "description": "WAF Rule Set Version" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } } }, "variables": { "publicIPAddressName": "publicIp1", "virtualNetworkName": "virtualNetwork1", "subnetName": "appGatewaySubnet", "subnet2Name": "workloadSubnet", "subnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets/', variables('virtualNetworkName'), variables('subnetName'))]", "publicIPRef": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]" }, "resources": [ { "apiVersion": "2019-04-01", "type": "Microsoft.Network/publicIPAddresses", "name": "[variables('publicIPAddressName')]", "location": "[parameters('location')]", "sku": { "name": "Standard" }, "properties": { "publicIPAllocationMethod": "Static" } }, { "apiVersion": "2019-04-01", "type": "Microsoft.Network/virtualNetworks", "name": "[variables('virtualNetworkName')]", "location": "[parameters('location')]", "properties": { "addressSpace": { "addressPrefixes": [ "[parameters('addressPrefix')]" ] }, "subnets": [ { "name": "[variables('subnetName')]", "properties": { "addressPrefix": "[parameters('subnetPrefix')]" } }, { "name": "[variables('subnet2Name')]", "properties": { "addressPrefix": "[parameters('subnet2Prefix')]" } } ] } }, { "apiVersion": "2019-04-01", "name": "[parameters('applicationGatewayName')]", "type": "Microsoft.Network/applicationGateways", "location": "[parameters('location')]", "dependsOn": [ "[variables('virtualNetworkName')]", "[variables('publicIPAddressName')]" ], "properties": { "sku": { "name": "[parameters('applicationGatewaySize')]", "tier": "[parameters('applicationGatewayTier')]", "capacity": "[parameters('capacity')]" }, "gatewayIPConfigurations": [ { "name": "appGatewayIpConfig", "properties": { "subnet": { "id": "[variables('subnetRef')]" } } } ], "frontendIPConfigurations": [ { "name": "appGatewayFrontendIP", "properties": { "PublicIPAddress": { "id": "[variables('publicIPRef')]" } } } ], "frontendPorts": [ { "name": "appGatewayFrontendPort", "properties": { "Port": 80 } } ], "backendAddressPools": [ { "name": "appGatewayBackendPool", "properties": { "BackendAddresses": [ { "IpAddress": "[parameters('backendIpAddress1')]" }, { "IpAddress": "[parameters('backendIpAddress2')]" } ] } } ], "backendHttpSettingsCollection": [ { "name": "appGatewayBackendHttpSettings", "properties": { "Port": 80, "Protocol": "Http", "CookieBasedAffinity": "Disabled" } } ], "httpListeners": [ { "name": "appGatewayHttpListener", "properties": { "FrontendIPConfiguration": { "Id": "[resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', parameters('applicationGatewayName'), 'appGatewayFrontendIP')]" }, "FrontendPort": { "Id": "[resourceId('Microsoft.Network/applicationGateways/frontendPorts', parameters('applicationGatewayName'), 'appGatewayFrontendPort')]" }, "Protocol": "Http", "SslCertificate": null } } ], "requestRoutingRules": [ { "Name": "rule1", "properties": { "RuleType": "Basic", "httpListener": { "id": "[resourceId('Microsoft.Network/applicationGateways/httpListeners', parameters('applicationGatewayName'), 'appGatewayHttpListener')]" }, "backendAddressPool": { "id": "[resourceId('Microsoft.Network/applicationGateways/backendAddressPools', parameters('applicationGatewayName'), 'appGatewayBackendPool')]" }, "backendHttpSettings": { "id": "[resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', parameters('applicationGatewayName'), 'appGatewayBackendHttpSettings')]" } } } ], "webApplicationFirewallConfiguration": { "enabled": "[parameters('wafEnabled')]", "firewallMode": "[parameters('wafMode')]", "ruleSetType": "[parameters('wafRuleSetType')]", "ruleSetVersion": "[parameters('wafRuleSetVersion')]" } } } ] } ================================================ FILE: templates/AZ-300/App-Gateway/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { } } ================================================ FILE: templates/AZ-300/AppService+Container/AppService+Container.deployproj ================================================  Debug AnyCPU Release AnyCPU 719c3044-fe01-45f1-9134-bf13bd4bedf3 False ================================================ FILE: templates/AZ-300/AppService+Container/Deploy-AzureResourceGroup.ps1 ================================================ #Requires -Version 3.0 Param( [string] [Parameter(Mandatory=$true)] $ResourceGroupLocation, [string] $ResourceGroupName = 'AZ-300', [switch] $UploadArtifacts, [string] $StorageAccountName, [string] $StorageContainerName = $ResourceGroupName.ToLowerInvariant() + '-stageartifacts', [string] $TemplateFile = 'azuredeploy.json', [string] $TemplateParametersFile = 'azuredeploy.parameters.json', [string] $ArtifactStagingDirectory = '.', [string] $DSCSourceFolder = 'DSC', [switch] $ValidateOnly ) try { [Microsoft.Azure.Common.Authentication.AzureSession]::ClientFactory.AddUserAgent("VSAzureTools-$UI$($host.name)".replace(' ','_'), '3.0.0') } catch { } $ErrorActionPreference = 'Stop' Set-StrictMode -Version 3 function Format-ValidationOutput { param ($ValidationOutput, [int] $Depth = 0) Set-StrictMode -Off return @($ValidationOutput | Where-Object { $_ -ne $null } | ForEach-Object { @(' ' * $Depth + ': ' + $_.Message) + @(Format-ValidationOutput @($_.Details) ($Depth + 1)) }) } $OptionalParameters = New-Object -TypeName Hashtable $TemplateFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateFile)) $TemplateParametersFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateParametersFile)) if ($UploadArtifacts) { # Convert relative paths to absolute paths if needed $ArtifactStagingDirectory = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $ArtifactStagingDirectory)) $DSCSourceFolder = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $DSCSourceFolder)) # Parse the parameter file and update the values of artifacts location and artifacts location SAS token if they are present $JsonParameters = Get-Content $TemplateParametersFile -Raw | ConvertFrom-Json if (($JsonParameters | Get-Member -Type NoteProperty 'parameters') -ne $null) { $JsonParameters = $JsonParameters.parameters } $ArtifactsLocationName = '_artifactsLocation' $ArtifactsLocationSasTokenName = '_artifactsLocationSasToken' $OptionalParameters[$ArtifactsLocationName] = $JsonParameters | Select -Expand $ArtifactsLocationName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore $OptionalParameters[$ArtifactsLocationSasTokenName] = $JsonParameters | Select -Expand $ArtifactsLocationSasTokenName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore # Create DSC configuration archive if (Test-Path $DSCSourceFolder) { $DSCSourceFilePaths = @(Get-ChildItem $DSCSourceFolder -File -Filter '*.ps1' | ForEach-Object -Process {$_.FullName}) foreach ($DSCSourceFilePath in $DSCSourceFilePaths) { $DSCArchiveFilePath = $DSCSourceFilePath.Substring(0, $DSCSourceFilePath.Length - 4) + '.zip' Publish-AzureRmVMDscConfiguration $DSCSourceFilePath -OutputArchivePath $DSCArchiveFilePath -Force -Verbose } } # Create a storage account name if none was provided if ($StorageAccountName -eq '') { $StorageAccountName = 'stage' + ((Get-AzureRmContext).Subscription.SubscriptionId).Replace('-', '').substring(0, 19) } $StorageAccount = (Get-AzureRmStorageAccount | Where-Object{$_.StorageAccountName -eq $StorageAccountName}) # Create the storage account if it doesn't already exist if ($StorageAccount -eq $null) { $StorageResourceGroupName = 'ARM_Deploy_Staging' New-AzureRmResourceGroup -Location "$ResourceGroupLocation" -Name $StorageResourceGroupName -Force $StorageAccount = New-AzureRmStorageAccount -StorageAccountName $StorageAccountName -Type 'Standard_LRS' -ResourceGroupName $StorageResourceGroupName -Location "$ResourceGroupLocation" } # Generate the value for artifacts location if it is not provided in the parameter file if ($OptionalParameters[$ArtifactsLocationName] -eq $null) { $OptionalParameters[$ArtifactsLocationName] = $StorageAccount.Context.BlobEndPoint + $StorageContainerName } # Copy files from the local storage staging location to the storage account container New-AzureStorageContainer -Name $StorageContainerName -Context $StorageAccount.Context -ErrorAction SilentlyContinue *>&1 $ArtifactFilePaths = Get-ChildItem $ArtifactStagingDirectory -Recurse -File | ForEach-Object -Process {$_.FullName} foreach ($SourcePath in $ArtifactFilePaths) { Set-AzureStorageBlobContent -File $SourcePath -Blob $SourcePath.Substring($ArtifactStagingDirectory.length + 1) ` -Container $StorageContainerName -Context $StorageAccount.Context -Force } # Generate a 4 hour SAS token for the artifacts location if one was not provided in the parameters file if ($OptionalParameters[$ArtifactsLocationSasTokenName] -eq $null) { $OptionalParameters[$ArtifactsLocationSasTokenName] = ConvertTo-SecureString -AsPlainText -Force ` (New-AzureStorageContainerSASToken -Container $StorageContainerName -Context $StorageAccount.Context -Permission r -ExpiryTime (Get-Date).AddHours(4)) } } # Create the resource group only when it doesn't already exist if ((Get-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -ErrorAction SilentlyContinue) -eq $null) { New-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -Force -ErrorAction Stop } if ($ValidateOnly) { $ErrorMessages = Format-ValidationOutput (Test-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName ` -TemplateFile $TemplateFile ` -TemplateParameterFile $TemplateParametersFile ` @OptionalParameters) if ($ErrorMessages) { Write-Output '', 'Validation returned the following errors:', @($ErrorMessages), '', 'Template is invalid.' } else { Write-Output '', 'Template is valid.' } } else { New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $TemplateFile).BaseName + '-' + ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm')) ` -ResourceGroupName $ResourceGroupName ` -TemplateFile $TemplateFile ` -TemplateParameterFile $TemplateParametersFile ` @OptionalParameters ` -Force -Verbose ` -ErrorVariable ErrorMessages if ($ErrorMessages) { Write-Output '', 'Template deployment returned the following errors:', @(@($ErrorMessages) | ForEach-Object { $_.Exception.Message.TrimEnd("`r`n") }) } } ================================================ FILE: templates/AZ-300/AppService+Container/Deployment.targets ================================================ Debug AnyCPU bin\$(Configuration)\ false true false None obj\ $(BaseIntermediateOutputPath)\ $(BaseIntermediateOutputPath)$(Configuration)\ $(IntermediateOutputPath)ProjectReferences $(ProjectReferencesOutputPath)\ true false false Always Never false Build _GetDeploymentProjectContent; _CalculateContentOutputRelativePaths; _GetReferencedProjectsOutput; _CalculateArtifactStagingDirectory; _CopyOutputToArtifactStagingDirectory; Configuration=$(Configuration);Platform=$(Platform) $([System.IO.Path]::GetFileNameWithoutExtension('%(ProjectReference.Identity)')) $(OutDir) $(OutputPath) $(ArtifactStagingDirectory)\ $(ArtifactStagingDirectory)staging\ $(Build_StagingDirectory) <_OriginalIdentity>%(DeploymentProjectContentOutput.Identity) <_RelativePath>$(_OriginalIdentity.Replace('$(MSBuildProjectDirectory)', '')) $(_RelativePath) PrepareForRun ================================================ FILE: templates/AZ-300/AppService+Container/README.md ================================================ # Deploy Sonarqube on a Linux web app with MySQL             This template provides a easy way to deploy a Sonarqube docker image on a Linux Web App with Azure database for MySQL. Notice once deployed Sonar can take a while to start due the creation of the initial empty database, it can even fail if you try to access it directly, allow to start it before accessing it or even adjust the tier for the webapp or MySQL accordingly. ================================================ FILE: templates/AZ-300/AppService+Container/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", "contentVersion": "1.0.0.0", "parameters": { "siteName": { "type": "string", "metadata": { "description": "Name of azure web app" } }, "servicePlanTier": { "type": "string", "allowedValues": [ "Basic", "Standard" ], "defaultValue": "Basic", "metadata": { "description": "Tier for Service Plan" } }, "servicePlanSku": { "type": "string", "allowedValues": [ "B1", "B2", "B3", "S1", "S2", "S3" ], "defaultValue": "S2", "metadata": { "description": "Size for Service Plan" } }, "administratorLogin": { "type": "string", "minLength": 1, "metadata": { "description": "Database administrator login name" } }, "administratorLoginPassword": { "type": "securestring", "minLength": 8, "metadata": { "description": "Database administrator password" } }, "databaseSkuCapacity": { "type": "int", "defaultValue": 2, "allowedValues": [ 2, 4, 8, 16, 32 ], "metadata": { "description": "Azure database for MySQL compute capacity in vCores (2,4,8,16,32)" } }, "databaseSkuName": { "type": "string", "defaultValue": "GP_Gen5_2", "allowedValues": [ "GP_Gen5_2", "GP_Gen5_4", "GP_Gen5_8", "GP_Gen5_16", "GP_Gen5_32", "MO_Gen5_2", "MO_Gen5_4", "MO_Gen5_8", "MO_Gen5_16" ], "metadata": { "description": "Azure database for MySQL sku name " } }, "databaseSkuSizeMB": { "type": "int", "allowedValues": [ 102400, 51200 ], "defaultValue": 51200, "metadata": { "description": "Azure database for MySQL Sku Size " } }, "databaseSkuTier": { "type": "string", "defaultValue": "GeneralPurpose", "allowedValues": [ "GeneralPurpose", "MemoryOptimized" ], "metadata": { "description": "Azure database for MySQL pricing tier" } }, "mysqlVersion": { "type": "string", "allowedValues": [ "5.6", "5.7" ], "defaultValue": "5.7", "metadata": { "description": "MySQL version" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all the resources" } }, "databaseSkuFamily": { "type": "string", "defaultValue": "Gen5", "metadata": { "description": "Azure database for MySQL sku family" } } }, "variables": { "databaseName": "[concat(parameters('siteName'), 'database')]", "serverName": "[concat(parameters('siteName'), 'mysqlserver')]", "jdbcSonarUserName": "[concat(parameters('administratorLogin'),'@',variables('serverName'))]", "hostingPlanName": "[concat(parameters('siteName'), 'serviceplan')]" }, "resources": [ { "comments": "This is the Linux web app with the Sonarquebe Docker image and the DB", "type": "Microsoft.Web/sites", "name": "[parameters('siteName')]", "apiVersion": "2018-02-01", "location": "[parameters('location')]", "dependsOn": [ "[variables('hostingPlanName')]", "[variables('databaseName')]" ], "properties": { "siteConfig": { "linuxFxVersion": "DOCKER|SONARQUBE" }, "name": "[parameters('siteName')]", "serverFarmId": "[variables('hostingPlanName')]", "hostingEnvironment": "" }, "resources": [ { "name": "appsettings", "type": "config", "apiVersion": "2018-02-01", "comments": "This are the generated settings for the Sonar jdbc connectionstring", "dependsOn": [ "[resourceId('Microsoft.Web/sites', parameters('siteName'))]" ], "tags": { "displayName": "SonarappSettings" }, "properties": { "SONARQUBE_JDBC_URL": "[concat('jdbc:mysql://', reference(resourceId('Microsoft.DBforMySQL/servers',variables('serverName'))).fullyQualifiedDomainName , ':3306/',variables('databaseName'),'?verifyServerCertificate=true&useSSL=true&requireSSL=false&useUnicode=true&characterEncoding=utf8')]", "SONARQUBE_JDBC_USERNAME": "[variables('jdbcSonarUserName')]", "SONARQUBE_JDBC_PASSWORD": "[parameters('administratorLoginPassword')]" } } ] }, { "apiVersion": "2017-08-01", "name": "[variables('hostingPlanName')]", "type": "Microsoft.Web/serverfarms", "location": "[resourceGroup().location]", "properties": { "name": "[variables('hostingPlanName')]", "workerSizeId": "1", "reserved": true, "numberOfWorkers": "1", "hostingEnvironment": "" }, "sku": { "Tier": "[parameters('servicePlanTier')]", "Name": "[parameters('servicePlanSku')]" }, "kind": "linux" }, { "apiVersion": "2017-12-01", "kind": "", "location": "[resourceGroup().location]", "name": "[variables('serverName')]", "type": "Microsoft.DBforMySQL/servers", "sku": { "name": "[parameters('databaseSkuName')]", "tier": "[parameters('databaseSkuTier')]", "capacity": "[parameters('databaseSkuCapacity')]", "size": "[parameters('databaseSkuSizeMB')]", "family": "[parameters('databaseSkuFamily')]" }, "properties": { "version": "[parameters('mysqlVersion')]", "administratorLogin": "[parameters('administratorLogin')]", "administratorLoginPassword": "[parameters('administratorLoginPassword')]", "storageMB": "[parameters('databaseSkuSizeMB')]" }, "resources": [ { "type": "firewallrules", "apiVersion": "2017-12-01", "dependsOn": [ "[concat('Microsoft.DBforMySQL/servers/', variables('serverName'))]" ], "location": "[resourceGroup().location]", "name": "[concat(variables('serverName'),'firewall')]", "properties": { "startIpAddress": "0.0.0.0", "endIpAddress": "255.255.255.255" } }, { "name": "[variables('databaseName')]", "type": "databases", "apiVersion": "2017-12-01", "properties": { "charset": "utf8", "collation": "utf8_general_ci" }, "dependsOn": [ "[concat('Microsoft.DBforMySQL/servers/', variables('serverName'))]" ] } ] } ] } ================================================ FILE: templates/AZ-300/AppService+Container/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "siteName": { "value": null }, "administratorLogin": { "value": null } } } ================================================ FILE: templates/AZ-300/Deploy-AzureResourceGroup.ps1 ================================================ #Requires -Version 3.0 Param( [string] [Parameter(Mandatory=$true)] $ResourceGroupLocation, [string] $ResourceGroupName = 'AZ-300', [switch] $UploadArtifacts, [string] $StorageAccountName, [string] $StorageContainerName = $ResourceGroupName.ToLowerInvariant() + '-stageartifacts', [string] $TemplateFile = 'azuredeploy.json', [string] $TemplateParametersFile = 'azuredeploy.parameters.json', [string] $ArtifactStagingDirectory = '.', [string] $DSCSourceFolder = 'DSC', [switch] $ValidateOnly ) try { [Microsoft.Azure.Common.Authentication.AzureSession]::ClientFactory.AddUserAgent("VSAzureTools-$UI$($host.name)".replace(' ','_'), '3.0.0') } catch { } $ErrorActionPreference = 'Stop' Set-StrictMode -Version 3 function Format-ValidationOutput { param ($ValidationOutput, [int] $Depth = 0) Set-StrictMode -Off return @($ValidationOutput | Where-Object { $_ -ne $null } | ForEach-Object { @(' ' * $Depth + ': ' + $_.Message) + @(Format-ValidationOutput @($_.Details) ($Depth + 1)) }) } $OptionalParameters = New-Object -TypeName Hashtable $TemplateFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateFile)) $TemplateParametersFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateParametersFile)) if ($UploadArtifacts) { # Convert relative paths to absolute paths if needed $ArtifactStagingDirectory = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $ArtifactStagingDirectory)) $DSCSourceFolder = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $DSCSourceFolder)) # Parse the parameter file and update the values of artifacts location and artifacts location SAS token if they are present $JsonParameters = Get-Content $TemplateParametersFile -Raw | ConvertFrom-Json if (($JsonParameters | Get-Member -Type NoteProperty 'parameters') -ne $null) { $JsonParameters = $JsonParameters.parameters } $ArtifactsLocationName = '_artifactsLocation' $ArtifactsLocationSasTokenName = '_artifactsLocationSasToken' $OptionalParameters[$ArtifactsLocationName] = $JsonParameters | Select -Expand $ArtifactsLocationName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore $OptionalParameters[$ArtifactsLocationSasTokenName] = $JsonParameters | Select -Expand $ArtifactsLocationSasTokenName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore # Create DSC configuration archive if (Test-Path $DSCSourceFolder) { $DSCSourceFilePaths = @(Get-ChildItem $DSCSourceFolder -File -Filter '*.ps1' | ForEach-Object -Process {$_.FullName}) foreach ($DSCSourceFilePath in $DSCSourceFilePaths) { $DSCArchiveFilePath = $DSCSourceFilePath.Substring(0, $DSCSourceFilePath.Length - 4) + '.zip' Publish-AzureRmVMDscConfiguration $DSCSourceFilePath -OutputArchivePath $DSCArchiveFilePath -Force -Verbose } } # Create a storage account name if none was provided if ($StorageAccountName -eq '') { $StorageAccountName = 'stage' + ((Get-AzureRmContext).Subscription.SubscriptionId).Replace('-', '').substring(0, 19) } $StorageAccount = (Get-AzureRmStorageAccount | Where-Object{$_.StorageAccountName -eq $StorageAccountName}) # Create the storage account if it doesn't already exist if ($StorageAccount -eq $null) { $StorageResourceGroupName = 'ARM_Deploy_Staging' New-AzureRmResourceGroup -Location "$ResourceGroupLocation" -Name $StorageResourceGroupName -Force $StorageAccount = New-AzureRmStorageAccount -StorageAccountName $StorageAccountName -Type 'Standard_LRS' -ResourceGroupName $StorageResourceGroupName -Location "$ResourceGroupLocation" } # Generate the value for artifacts location if it is not provided in the parameter file if ($OptionalParameters[$ArtifactsLocationName] -eq $null) { $OptionalParameters[$ArtifactsLocationName] = $StorageAccount.Context.BlobEndPoint + $StorageContainerName } # Copy files from the local storage staging location to the storage account container New-AzureStorageContainer -Name $StorageContainerName -Context $StorageAccount.Context -ErrorAction SilentlyContinue *>&1 $ArtifactFilePaths = Get-ChildItem $ArtifactStagingDirectory -Recurse -File | ForEach-Object -Process {$_.FullName} foreach ($SourcePath in $ArtifactFilePaths) { Set-AzureStorageBlobContent -File $SourcePath -Blob $SourcePath.Substring($ArtifactStagingDirectory.length + 1) ` -Container $StorageContainerName -Context $StorageAccount.Context -Force } # Generate a 4 hour SAS token for the artifacts location if one was not provided in the parameters file if ($OptionalParameters[$ArtifactsLocationSasTokenName] -eq $null) { $OptionalParameters[$ArtifactsLocationSasTokenName] = ConvertTo-SecureString -AsPlainText -Force ` (New-AzureStorageContainerSASToken -Container $StorageContainerName -Context $StorageAccount.Context -Permission r -ExpiryTime (Get-Date).AddHours(4)) } } # Create the resource group only when it doesn't already exist if ((Get-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -ErrorAction SilentlyContinue) -eq $null) { New-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -Force -ErrorAction Stop } if ($ValidateOnly) { $ErrorMessages = Format-ValidationOutput (Test-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName ` -TemplateFile $TemplateFile ` -TemplateParameterFile $TemplateParametersFile ` @OptionalParameters) if ($ErrorMessages) { Write-Output '', 'Validation returned the following errors:', @($ErrorMessages), '', 'Template is invalid.' } else { Write-Output '', 'Template is valid.' } } else { New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $TemplateFile).BaseName + '-' + ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm')) ` -ResourceGroupName $ResourceGroupName ` -TemplateFile $TemplateFile ` -TemplateParameterFile $TemplateParametersFile ` @OptionalParameters ` -Force -Verbose ` -ErrorVariable ErrorMessages if ($ErrorMessages) { Write-Output '', 'Template deployment returned the following errors:', @(@($ErrorMessages) | ForEach-Object { $_.Exception.Message.TrimEnd("`r`n") }) } } ================================================ FILE: templates/AZ-300/Deployment.targets ================================================ Debug AnyCPU bin\$(Configuration)\ false true false None obj\ $(BaseIntermediateOutputPath)\ $(BaseIntermediateOutputPath)$(Configuration)\ $(IntermediateOutputPath)ProjectReferences $(ProjectReferencesOutputPath)\ true false false Always Never false Build _GetDeploymentProjectContent; _CalculateContentOutputRelativePaths; _GetReferencedProjectsOutput; _CalculateArtifactStagingDirectory; _CopyOutputToArtifactStagingDirectory; Configuration=$(Configuration);Platform=$(Platform) $([System.IO.Path]::GetFileNameWithoutExtension('%(ProjectReference.Identity)')) $(OutDir) $(OutputPath) $(ArtifactStagingDirectory)\ $(ArtifactStagingDirectory)staging\ $(Build_StagingDirectory) <_OriginalIdentity>%(DeploymentProjectContentOutput.Identity) <_RelativePath>$(_OriginalIdentity.Replace('$(MSBuildProjectDirectory)', '')) $(_RelativePath) PrepareForRun ================================================ FILE: templates/AZ-300/KeyVault/Deploy-AzureResourceGroup.ps1 ================================================ #Requires -Version 3.0 Param( [string] [Parameter(Mandatory=$true)] $ResourceGroupLocation, [string] $ResourceGroupName = 'AZ-300', [switch] $UploadArtifacts, [string] $StorageAccountName, [string] $StorageContainerName = $ResourceGroupName.ToLowerInvariant() + '-stageartifacts', [string] $TemplateFile = 'azuredeploy.json', [string] $TemplateParametersFile = 'azuredeploy.parameters.json', [string] $ArtifactStagingDirectory = '.', [string] $DSCSourceFolder = 'DSC', [switch] $ValidateOnly ) try { [Microsoft.Azure.Common.Authentication.AzureSession]::ClientFactory.AddUserAgent("VSAzureTools-$UI$($host.name)".replace(' ','_'), '3.0.0') } catch { } $ErrorActionPreference = 'Stop' Set-StrictMode -Version 3 function Format-ValidationOutput { param ($ValidationOutput, [int] $Depth = 0) Set-StrictMode -Off return @($ValidationOutput | Where-Object { $_ -ne $null } | ForEach-Object { @(' ' * $Depth + ': ' + $_.Message) + @(Format-ValidationOutput @($_.Details) ($Depth + 1)) }) } $OptionalParameters = New-Object -TypeName Hashtable $TemplateFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateFile)) $TemplateParametersFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateParametersFile)) if ($UploadArtifacts) { # Convert relative paths to absolute paths if needed $ArtifactStagingDirectory = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $ArtifactStagingDirectory)) $DSCSourceFolder = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $DSCSourceFolder)) # Parse the parameter file and update the values of artifacts location and artifacts location SAS token if they are present $JsonParameters = Get-Content $TemplateParametersFile -Raw | ConvertFrom-Json if (($JsonParameters | Get-Member -Type NoteProperty 'parameters') -ne $null) { $JsonParameters = $JsonParameters.parameters } $ArtifactsLocationName = '_artifactsLocation' $ArtifactsLocationSasTokenName = '_artifactsLocationSasToken' $OptionalParameters[$ArtifactsLocationName] = $JsonParameters | Select -Expand $ArtifactsLocationName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore $OptionalParameters[$ArtifactsLocationSasTokenName] = $JsonParameters | Select -Expand $ArtifactsLocationSasTokenName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore # Create DSC configuration archive if (Test-Path $DSCSourceFolder) { $DSCSourceFilePaths = @(Get-ChildItem $DSCSourceFolder -File -Filter '*.ps1' | ForEach-Object -Process {$_.FullName}) foreach ($DSCSourceFilePath in $DSCSourceFilePaths) { $DSCArchiveFilePath = $DSCSourceFilePath.Substring(0, $DSCSourceFilePath.Length - 4) + '.zip' Publish-AzureRmVMDscConfiguration $DSCSourceFilePath -OutputArchivePath $DSCArchiveFilePath -Force -Verbose } } # Create a storage account name if none was provided if ($StorageAccountName -eq '') { $StorageAccountName = 'stage' + ((Get-AzureRmContext).Subscription.SubscriptionId).Replace('-', '').substring(0, 19) } $StorageAccount = (Get-AzureRmStorageAccount | Where-Object{$_.StorageAccountName -eq $StorageAccountName}) # Create the storage account if it doesn't already exist if ($StorageAccount -eq $null) { $StorageResourceGroupName = 'ARM_Deploy_Staging' New-AzureRmResourceGroup -Location "$ResourceGroupLocation" -Name $StorageResourceGroupName -Force $StorageAccount = New-AzureRmStorageAccount -StorageAccountName $StorageAccountName -Type 'Standard_LRS' -ResourceGroupName $StorageResourceGroupName -Location "$ResourceGroupLocation" } # Generate the value for artifacts location if it is not provided in the parameter file if ($OptionalParameters[$ArtifactsLocationName] -eq $null) { $OptionalParameters[$ArtifactsLocationName] = $StorageAccount.Context.BlobEndPoint + $StorageContainerName } # Copy files from the local storage staging location to the storage account container New-AzureStorageContainer -Name $StorageContainerName -Context $StorageAccount.Context -ErrorAction SilentlyContinue *>&1 $ArtifactFilePaths = Get-ChildItem $ArtifactStagingDirectory -Recurse -File | ForEach-Object -Process {$_.FullName} foreach ($SourcePath in $ArtifactFilePaths) { Set-AzureStorageBlobContent -File $SourcePath -Blob $SourcePath.Substring($ArtifactStagingDirectory.length + 1) ` -Container $StorageContainerName -Context $StorageAccount.Context -Force } # Generate a 4 hour SAS token for the artifacts location if one was not provided in the parameters file if ($OptionalParameters[$ArtifactsLocationSasTokenName] -eq $null) { $OptionalParameters[$ArtifactsLocationSasTokenName] = ConvertTo-SecureString -AsPlainText -Force ` (New-AzureStorageContainerSASToken -Container $StorageContainerName -Context $StorageAccount.Context -Permission r -ExpiryTime (Get-Date).AddHours(4)) } } # Create the resource group only when it doesn't already exist if ((Get-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -ErrorAction SilentlyContinue) -eq $null) { New-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -Force -ErrorAction Stop } if ($ValidateOnly) { $ErrorMessages = Format-ValidationOutput (Test-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName ` -TemplateFile $TemplateFile ` -TemplateParameterFile $TemplateParametersFile ` @OptionalParameters) if ($ErrorMessages) { Write-Output '', 'Validation returned the following errors:', @($ErrorMessages), '', 'Template is invalid.' } else { Write-Output '', 'Template is valid.' } } else { New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $TemplateFile).BaseName + '-' + ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm')) ` -ResourceGroupName $ResourceGroupName ` -TemplateFile $TemplateFile ` -TemplateParameterFile $TemplateParametersFile ` @OptionalParameters ` -Force -Verbose ` -ErrorVariable ErrorMessages if ($ErrorMessages) { Write-Output '', 'Template deployment returned the following errors:', @(@($ErrorMessages) | ForEach-Object { $_.Exception.Message.TrimEnd("`r`n") }) } } ================================================ FILE: templates/AZ-300/KeyVault/Deployment.targets ================================================ Debug AnyCPU bin\$(Configuration)\ false true false None obj\ $(BaseIntermediateOutputPath)\ $(BaseIntermediateOutputPath)$(Configuration)\ $(IntermediateOutputPath)ProjectReferences $(ProjectReferencesOutputPath)\ true false false Always Never false Build _GetDeploymentProjectContent; _CalculateContentOutputRelativePaths; _GetReferencedProjectsOutput; _CalculateArtifactStagingDirectory; _CopyOutputToArtifactStagingDirectory; Configuration=$(Configuration);Platform=$(Platform) $([System.IO.Path]::GetFileNameWithoutExtension('%(ProjectReference.Identity)')) $(OutDir) $(OutputPath) $(ArtifactStagingDirectory)\ $(ArtifactStagingDirectory)staging\ $(Build_StagingDirectory) <_OriginalIdentity>%(DeploymentProjectContentOutput.Identity) <_RelativePath>$(_OriginalIdentity.Replace('$(MSBuildProjectDirectory)', '')) $(_RelativePath) PrepareForRun ================================================ FILE: templates/AZ-300/KeyVault/KeyVault.deployproj ================================================  Debug AnyCPU Release AnyCPU 043153b4-7c7d-4bcf-8b43-56782d6a3824 False ================================================ FILE: templates/AZ-300/KeyVault/README.md ================================================ # Create an Azure Key Vault and a list of secrets             This template creates a key vault with a multiple access policies, and a list of secrets. Instead of just using an array for the secret creation, this template wraps an array in a [secureObject](https://docs.microsoft.com/azure/azure-resource-manager/resource-group-authoring-templates#parameters). Using a secureObject instead of an array type means that the values you pass, cannot be read back in the portal after the deployment. Resource iteration is used in this template. For more information, see - [Create multiple instances](https://docs.microsoft.com/azure/azure-resource-manager/resource-group-create-multiple) - [Tutorial: create multiple instances](https://docs.microsoft.com/azure/azure-resource-manager/resource-manager-tutorial-create-multiple-instances) If you are new to Azure Key Vault, see: - [Azure Key Vault service](https://azure.microsoft.com/services/key-vault/) - [Azure Key Vault documentation](https://docs.microsoft.com/azure/key-vault/) - [Azure Key Vault template reference](https://docs.microsoft.com/azure/templates/microsoft.keyvault/allversions) - [Quickstart templates](https://azure.microsoft.com/resources/templates/?resourceType=Microsoft.Keyvault) If you are new to the template development, see: - [Azure Resource Manager documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/) - [Use Azure Key Vault to pass secure parameter value during deployment](https://docs.microsoft.com/azure/azure-resource-manager/resource-manager-keyvault-parameter) - [Tutorial: Integrate Azure Key Vault in Resource Manager Template deployment](https://docs.microsoft.com/azure/azure-resource-manager/resource-manager-tutorial-use-key-vault) Tags: Azure Key Vault, Key Vault, Secrets, Resource Manager, Resource Manager templates, ARM templates ================================================ FILE: templates/AZ-300/KeyVault/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "keyVaultName": { "type": "string", "metadata": { "description": "Specifies the name of the key vault." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Specifies the Azure location where the key vault should be created." } }, "enabledForDeployment": { "type": "bool", "defaultValue": false, "allowedValues": [ true, false ], "metadata": { "description": "Specifies whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault." } }, "enabledForDiskEncryption": { "type": "bool", "defaultValue": false, "allowedValues": [ true, false ], "metadata": { "description": "Specifies whether Azure Disk Encryption is permitted to retrieve secrets from the vault and unwrap keys." } }, "enabledForTemplateDeployment": { "type": "bool", "defaultValue": false, "allowedValues": [ true, false ], "metadata": { "description": "Specifies whether Azure Resource Manager is permitted to retrieve secrets from the key vault." } }, "tenantId": { "type": "string", "defaultValue": "[subscription().tenantId]", "metadata": { "description": "Specifies the Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. Get it by using Get-AzSubscription cmdlet." } }, "objectId": { "type": "string", "metadata": { "description": "Specifies the object ID of a user, service principal or security group in the Azure Active Directory tenant for the vault. The object ID must be unique for the list of access policies. Get it by using Get-AzADUser or Get-AzADServicePrincipal cmdlets." } }, "keysPermissions": { "type": "array", "defaultValue": [ "list" ], "metadata": { "description": "Specifies the permissions to keys in the vault. Valid values are: all, encrypt, decrypt, wrapKey, unwrapKey, sign, verify, get, list, create, update, import, delete, backup, restore, recover, and purge." } }, "secretsPermissions": { "type": "array", "defaultValue": [ "list" ], "metadata": { "description": "Specifies the permissions to secrets in the vault. Valid values are: all, get, list, set, delete, backup, restore, recover, and purge." } }, "skuName": { "type": "string", "defaultValue": "Standard", "allowedValues": [ "Standard", "Premium" ], "metadata": { "description": "Specifies whether the key vault is a standard vault or a premium vault." } }, "secretsObject": { "type": "secureObject", "defaultValue": "{}", "metadata": { "description": "Specifies all secrets {\"secretName\":\"\",\"secretValue\":\"\"} wrapped in a secure object." } } }, "resources": [ { "type": "Microsoft.KeyVault/vaults", "name": "[parameters('keyVaultName')]", "location": "[parameters('location')]", "apiVersion": "2018-02-14", "tags": { "displayName": "KeyVault" }, "properties": { "enabledForDeployment": "[parameters('enabledForDeployment')]", "enabledForTemplateDeployment": "[parameters('enabledForTemplateDeployment')]", "enabledForDiskEncryption": "[parameters('enabledForDiskEncryption')]", "tenantId": "[parameters('tenantId')]", "accessPolicies": [ { "objectId": "[parameters('objectId')]", "tenantId": "[parameters('tenantId')]", "permissions": { "keys": "[parameters('keysPermissions')]", "secrets": "[parameters('secretsPermissions')]" } } ], "sku": { "name": "[parameters('skuName')]", "family": "A" }, "networkAcls": { "defaultAction": "Allow", "bypass": "AzureServices" } } }, { "type": "Microsoft.KeyVault/vaults/secrets", "name": "[concat(parameters('keyVaultName'), '/', parameters('secretsObject').secrets[copyIndex()].secretName)]", "apiVersion": "2018-02-14", "dependsOn": [ "[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]" ], "copy": { "name": "secretsCopy", "count": "[length(parameters('secretsObject').secrets)]" }, "properties": { "value": "[parameters('secretsObject').secrets[copyIndex()].secretValue]" } } ] } ================================================ FILE: templates/AZ-300/KeyVault/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "keyVaultName": { "value": null }, "objectId": { "value": null } } } ================================================ FILE: templates/AZ-300/README.md ================================================ # Multi VM Template with Managed Disk             This template will provision N number of virtual machines with your choice in a single VNET. Every VM will be provisioned with a Network Interface and a Public IP resource. All the VMs will be provisioned in a single Availability Set. A single storage account will be provisioned to store the diagnostic information. If you provision 3 VM’s with this template, your resources will look like below in the resource group. ![template resources](images/resources.png "template resource objects") `Tags:Managed Disks, Azure VMs, Copy Index` ================================================ FILE: templates/AZ-300/VM Copy Loops.deployproj ================================================  Debug AnyCPU Release AnyCPU d668f964-6f42-4175-8457-4ea99fb2e61f False ================================================ FILE: templates/AZ-300/WebApp+SQL/Deploy-AzureResourceGroup.ps1 ================================================ #Requires -Version 3.0 Param( [string] [Parameter(Mandatory=$true)] $ResourceGroupLocation, [string] $ResourceGroupName = 'AZ-300', [switch] $UploadArtifacts, [string] $StorageAccountName, [string] $StorageContainerName = $ResourceGroupName.ToLowerInvariant() + '-stageartifacts', [string] $TemplateFile = 'azuredeploy.json', [string] $TemplateParametersFile = 'azuredeploy.parameters.json', [string] $ArtifactStagingDirectory = '.', [string] $DSCSourceFolder = 'DSC', [switch] $ValidateOnly ) try { [Microsoft.Azure.Common.Authentication.AzureSession]::ClientFactory.AddUserAgent("VSAzureTools-$UI$($host.name)".replace(' ','_'), '3.0.0') } catch { } $ErrorActionPreference = 'Stop' Set-StrictMode -Version 3 function Format-ValidationOutput { param ($ValidationOutput, [int] $Depth = 0) Set-StrictMode -Off return @($ValidationOutput | Where-Object { $_ -ne $null } | ForEach-Object { @(' ' * $Depth + ': ' + $_.Message) + @(Format-ValidationOutput @($_.Details) ($Depth + 1)) }) } $OptionalParameters = New-Object -TypeName Hashtable $TemplateFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateFile)) $TemplateParametersFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateParametersFile)) if ($UploadArtifacts) { # Convert relative paths to absolute paths if needed $ArtifactStagingDirectory = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $ArtifactStagingDirectory)) $DSCSourceFolder = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $DSCSourceFolder)) # Parse the parameter file and update the values of artifacts location and artifacts location SAS token if they are present $JsonParameters = Get-Content $TemplateParametersFile -Raw | ConvertFrom-Json if (($JsonParameters | Get-Member -Type NoteProperty 'parameters') -ne $null) { $JsonParameters = $JsonParameters.parameters } $ArtifactsLocationName = '_artifactsLocation' $ArtifactsLocationSasTokenName = '_artifactsLocationSasToken' $OptionalParameters[$ArtifactsLocationName] = $JsonParameters | Select -Expand $ArtifactsLocationName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore $OptionalParameters[$ArtifactsLocationSasTokenName] = $JsonParameters | Select -Expand $ArtifactsLocationSasTokenName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore # Create DSC configuration archive if (Test-Path $DSCSourceFolder) { $DSCSourceFilePaths = @(Get-ChildItem $DSCSourceFolder -File -Filter '*.ps1' | ForEach-Object -Process {$_.FullName}) foreach ($DSCSourceFilePath in $DSCSourceFilePaths) { $DSCArchiveFilePath = $DSCSourceFilePath.Substring(0, $DSCSourceFilePath.Length - 4) + '.zip' Publish-AzureRmVMDscConfiguration $DSCSourceFilePath -OutputArchivePath $DSCArchiveFilePath -Force -Verbose } } # Create a storage account name if none was provided if ($StorageAccountName -eq '') { $StorageAccountName = 'stage' + ((Get-AzureRmContext).Subscription.SubscriptionId).Replace('-', '').substring(0, 19) } $StorageAccount = (Get-AzureRmStorageAccount | Where-Object{$_.StorageAccountName -eq $StorageAccountName}) # Create the storage account if it doesn't already exist if ($StorageAccount -eq $null) { $StorageResourceGroupName = 'ARM_Deploy_Staging' New-AzureRmResourceGroup -Location "$ResourceGroupLocation" -Name $StorageResourceGroupName -Force $StorageAccount = New-AzureRmStorageAccount -StorageAccountName $StorageAccountName -Type 'Standard_LRS' -ResourceGroupName $StorageResourceGroupName -Location "$ResourceGroupLocation" } # Generate the value for artifacts location if it is not provided in the parameter file if ($OptionalParameters[$ArtifactsLocationName] -eq $null) { $OptionalParameters[$ArtifactsLocationName] = $StorageAccount.Context.BlobEndPoint + $StorageContainerName } # Copy files from the local storage staging location to the storage account container New-AzureStorageContainer -Name $StorageContainerName -Context $StorageAccount.Context -ErrorAction SilentlyContinue *>&1 $ArtifactFilePaths = Get-ChildItem $ArtifactStagingDirectory -Recurse -File | ForEach-Object -Process {$_.FullName} foreach ($SourcePath in $ArtifactFilePaths) { Set-AzureStorageBlobContent -File $SourcePath -Blob $SourcePath.Substring($ArtifactStagingDirectory.length + 1) ` -Container $StorageContainerName -Context $StorageAccount.Context -Force } # Generate a 4 hour SAS token for the artifacts location if one was not provided in the parameters file if ($OptionalParameters[$ArtifactsLocationSasTokenName] -eq $null) { $OptionalParameters[$ArtifactsLocationSasTokenName] = ConvertTo-SecureString -AsPlainText -Force ` (New-AzureStorageContainerSASToken -Container $StorageContainerName -Context $StorageAccount.Context -Permission r -ExpiryTime (Get-Date).AddHours(4)) } } # Create the resource group only when it doesn't already exist if ((Get-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -ErrorAction SilentlyContinue) -eq $null) { New-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -Force -ErrorAction Stop } if ($ValidateOnly) { $ErrorMessages = Format-ValidationOutput (Test-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName ` -TemplateFile $TemplateFile ` -TemplateParameterFile $TemplateParametersFile ` @OptionalParameters) if ($ErrorMessages) { Write-Output '', 'Validation returned the following errors:', @($ErrorMessages), '', 'Template is invalid.' } else { Write-Output '', 'Template is valid.' } } else { New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $TemplateFile).BaseName + '-' + ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm')) ` -ResourceGroupName $ResourceGroupName ` -TemplateFile $TemplateFile ` -TemplateParameterFile $TemplateParametersFile ` @OptionalParameters ` -Force -Verbose ` -ErrorVariable ErrorMessages if ($ErrorMessages) { Write-Output '', 'Template deployment returned the following errors:', @(@($ErrorMessages) | ForEach-Object { $_.Exception.Message.TrimEnd("`r`n") }) } } ================================================ FILE: templates/AZ-300/WebApp+SQL/Deployment.targets ================================================ Debug AnyCPU bin\$(Configuration)\ false true false None obj\ $(BaseIntermediateOutputPath)\ $(BaseIntermediateOutputPath)$(Configuration)\ $(IntermediateOutputPath)ProjectReferences $(ProjectReferencesOutputPath)\ true false false Always Never false Build _GetDeploymentProjectContent; _CalculateContentOutputRelativePaths; _GetReferencedProjectsOutput; _CalculateArtifactStagingDirectory; _CopyOutputToArtifactStagingDirectory; Configuration=$(Configuration);Platform=$(Platform) $([System.IO.Path]::GetFileNameWithoutExtension('%(ProjectReference.Identity)')) $(OutDir) $(OutputPath) $(ArtifactStagingDirectory)\ $(ArtifactStagingDirectory)staging\ $(Build_StagingDirectory) <_OriginalIdentity>%(DeploymentProjectContentOutput.Identity) <_RelativePath>$(_OriginalIdentity.Replace('$(MSBuildProjectDirectory)', '')) $(_RelativePath) PrepareForRun ================================================ FILE: templates/AZ-300/WebApp+SQL/README.md ================================================ # Provision a web app with a SQL Database             This sample creates a free Azure Web App and SQL Database at the "Basic" service level. The template can support other tiers of service, details for each service can be found here: ### Microsoft App Services - [App Service Pricing](https://azure.microsoft.com/pricing/details/app-service/) ### Microsoft SQL - [SQL Database Pricing](https://azure.microsoft.com/pricing/details/sql-database/) For more information about using this template, see [Provision a web app with a SQL Database](https://azure.microsoft.com/documentation/articles/app-service-web-arm-with-sql-database-provision/). ### Microsoft Learn Resources - [Learn SQL Server](https://docs.microsoft.com/learn/browse/?term=SQL) - [Learn App Services](https://docs.microsoft.com/en-us/learn/browse/?term=web%20app) ================================================ FILE: templates/AZ-300/WebApp+SQL/WebApp+SQL.deployproj ================================================  Debug AnyCPU Release AnyCPU 8cd8c986-6352-439e-b8f2-96e0b6882933 False ================================================ FILE: templates/AZ-300/WebApp+SQL/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "skuName": { "type": "string", "defaultValue": "S1", "allowedValues": [ "F1", "D1", "B1", "B2", "B3", "S1", "S2", "S3", "P1", "P2", "P3", "P4" ], "metadata": { "description": "Describes plan's pricing tier and instance size. Check details at https://azure.microsoft.com/en-us/pricing/details/app-service/" } }, "skuCapacity": { "type": "int", "defaultValue": 1, "minValue": 1, "maxValue": 3, "metadata": { "description": "Describes plan's instance count" } }, "sqlAdministratorLogin": { "type": "string", "metadata": { "description": "The admin user of the SQL Server" } }, "sqlAdministratorLoginPassword": { "type": "securestring", "metadata": { "description": "The password of the admin user of the SQL Server" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } } }, "variables": { "hostingPlanName": "[concat('hostingplan', uniqueString(resourceGroup().id))]", "webSiteName": "[concat('webSite', uniqueString(resourceGroup().id))]", "sqlserverName": "[concat('sqlserver', uniqueString(resourceGroup().id))]", "databaseName": "sampledb" }, "resources": [ { "name": "[variables('sqlserverName')]", "type": "Microsoft.Sql/servers", "location": "[parameters('location')]", "tags": { "displayName": "SqlServer" }, "apiVersion": "2018-06-01-preview", "properties": { "administratorLogin": "[parameters('sqlAdministratorLogin')]", "administratorLoginPassword": "[parameters('sqlAdministratorLoginPassword')]", "version": "12.0" }, "resources": [ { "name": "[variables('databaseName')]", "type": "databases", "location": "[parameters('location')]", "tags": { "displayName": "Database" }, "apiVersion": "2018-06-01-preview", "dependsOn": [ "[variables('sqlserverName')]" ], "properties": { "edition": "Basic", "collation": "SQL_Latin1_General_CP1_CI_AS", "maxSizeBytes": "1073741824", "requestedServiceObjectiveName": "Basic" } }, { "type": "firewallrules", "apiVersion": "2018-06-01-preview", "dependsOn": [ "[variables('sqlserverName')]" ], "location": "[parameters('location')]", "name": "AllowAllWindowsAzureIps", "properties": { "endIpAddress": "0.0.0.0", "startIpAddress": "0.0.0.0" } } ] }, { "apiVersion": "2018-02-01", "name": "[variables('hostingPlanName')]", "type": "Microsoft.Web/serverfarms", "location": "[parameters('location')]", "tags": { "displayName": "HostingPlan" }, "sku": { "name": "[parameters('skuName')]", "capacity": "[parameters('skuCapacity')]" }, "properties": { "name": "[variables('hostingPlanName')]" } }, { "apiVersion": "2018-02-01", "name": "[variables('webSiteName')]", "type": "Microsoft.Web/sites", "location": "[parameters('location')]", "dependsOn": [ "[variables('hostingPlanName')]" ], "tags": { "[concat('hidden-related:', resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName')))]": "empty", "displayName": "Website" }, "properties": { "name": "[variables('webSiteName')]", "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]" }, "resources": [ { "apiVersion": "2018-02-01", "type": "config", "name": "connectionstrings", "dependsOn": [ "[variables('webSiteName')]" ], "properties": { "DefaultConnection": { "value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', variables('sqlserverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', variables('databaseName'), ';User Id=', parameters('sqlAdministratorLogin'), '@', reference(concat('Microsoft.Sql/servers/', variables('sqlserverName'))).fullyQualifiedDomainName, ';Password=', parameters('sqlAdministratorLoginPassword'), ';')]", "type": "SQLAzure" } } } ] }, { "apiVersion": "2018-05-01-preview", "name": "[concat('AppInsights', variables('webSiteName'))]", "type": "Microsoft.Insights/components", "location": "[parameters('location')]", "dependsOn": [ "[variables('webSiteName')]" ], "tags": { "[concat('hidden-link:', resourceId('Microsoft.Web/sites', variables('webSiteName')))]": "Resource", "displayName": "AppInsightsComponent" }, "properties": { "ApplicationId": "[variables('webSiteName')]" } } ] } ================================================ FILE: templates/AZ-300/WebApp+SQL/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "sqlAdministratorLogin": { "value": "tim" }, "skuName": { "value": "S1" } } } ================================================ FILE: templates/AZ-300/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "virtualMachineAdminUserName": { "defaultValue": "azadmin", "type": "string", "metadata": { "description": "Administrator Username for the local admin account" } }, "virtualMachineAdminPassword": { "type": "securestring", "metadata": { "description": "Administrator password for the local admin account" } }, "virtualMachineNamePrefix": { "defaultValue": "MyVM0", "type": "string", "maxLength": 15, "metadata": { "description": "Name of the virtual machine to be created" } }, "virtualMachineCount": { "type": "int", "defaultValue": 3, "metadata": { "description": "Number of virtual machines to be created" } }, "virtualMachineSize": { "type": "string", "defaultValue": "Standard_DS2_v2", "allowedValues": [ "Standard_DS1_v2", "Standard_DS2_v2", "Standard_DS3_v2", "Standard_DS4_v2", "Standard_DS5_v2" ], "metadata": { "description": "Virtual Machine Size" } }, "operatingSystem": { "type": "string", "defaultValue": "Server2016", "metadata": { "description": "Operating System of the Server" }, "allowedValues": [ "Server2012R2", "Server2016" ] }, "availabilitySetName": { "defaultValue": "MyAvailabilitySet", "type": "string", "metadata": { "description": "Availability Set Name where the VM will be placed" } }, "dnsPrefixForPublicIP": { "type": "string", "minLength": 1, "maxLength": 14, "defaultValue": "[uniqueString(resourceGroup().id)]", "metadata": { "description": "Globally unique DNS prefix for the Public IPs used to access the Virtual Machines" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } } }, "variables": { "myVNETName": "myVNET", "myVNETPrefix": "10.0.0.0/16", "myVNETSubnet1Name": "Subnet1", "myVNETSubnet1Prefix": "10.0.0.0/24", "diagnosticStorageAccountName": "[concat('diagst', uniqueString(resourceGroup().id))]", "operatingSystemValues": { "Server2012R2": { "PublisherValue": "MicrosoftWindowsServer", "OfferValue": "WindowsServer", "SkuValue": "2012-R2-Datacenter" }, "Server2016": { "PublisherValue": "MicrosoftWindowsServer", "OfferValue": "WindowsServer", "SkuValue": "2016-Datacenter" } }, "availabilitySetPlatformFaultDomainCount": "2", "availabilitySetPlatformUpdateDomainCount": "5", "subnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('myVNETName'), variables('myVNETSubnet1Name'))]", "networkSecurityGroupName": "default-NSG" }, "resources": [ { "comments": "Default Network Security Group for template", "type": "Microsoft.Network/networkSecurityGroups", "apiVersion": "2019-08-01", "name": "[variables('networkSecurityGroupName')]", "location": "[parameters('location')]", "properties": { "securityRules": [ { "name": "default-allow-3389", "properties": { "priority": 1000, "access": "Allow", "direction": "Inbound", "destinationPortRange": "3389", "protocol": "Tcp", "sourceAddressPrefix": "*", "sourcePortRange": "*", "destinationAddressPrefix": "*" } } ] } }, { "name": "[variables('myVNETName')]", "type": "Microsoft.Network/virtualNetworks", "location": "[parameters('location')]", "apiVersion": "2016-03-30", "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" ], "tags": { "displayName": "[variables('myVNETName')]" }, "properties": { "addressSpace": { "addressPrefixes": [ "[variables('myVNETPrefix')]" ] }, "subnets": [ { "name": "[variables('myVNETSubnet1Name')]", "properties": { "addressPrefix": "[variables('myVNETSubnet1Prefix')]", "networkSecurityGroup": { "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" } } } ] } }, { "name": "[variables('diagnosticStorageAccountName')]", "type": "Microsoft.Storage/storageAccounts", "location": "[parameters('location')]", "apiVersion": "2016-01-01", "sku": { "name": "Standard_LRS" }, "dependsOn": [], "tags": { "displayName": "diagnosticStorageAccount" }, "kind": "Storage" }, { "type": "Microsoft.Compute/availabilitySets", "name": "[parameters('availabilitySetName')]", "apiVersion": "2017-03-30", "location": "[parameters('location')]", "properties": { "platformFaultDomainCount": "[variables('availabilitySetPlatformFaultDomainCount')]", "platformUpdateDomainCount": "[variables('availabilitySetPlatformUpdateDomainCount')]" }, "sku": { "name": "Aligned" } }, { "type": "Microsoft.Compute/virtualMachines", "name": "[concat(parameters('virtualMachineNamePrefix'), copyIndex(1))]", "apiVersion": "2017-03-30", "location": "[parameters('location')]", "copy": { "name": "VMcopy", "count": "[parameters('virtualMachineCount')]" }, "properties": { "hardwareProfile": { "vmSize": "[parameters('virtualMachineSize')]" }, "storageProfile": { "imageReference": { "publisher": "[variables('operatingSystemValues')[parameters('operatingSystem')].PublisherValue]", "offer": "[variables('operatingSystemValues')[parameters('operatingSystem')].OfferValue]", "sku": "[variables('operatingSystemValues')[parameters('operatingSystem')].SkuValue]", "version": "latest" }, "osDisk": { "name": "[concat(parameters('virtualMachineNamePrefix'),copyIndex(1))]", "createOption": "FromImage", "managedDisk": { "storageAccountType": "Premium_LRS" }, "caching": "ReadWrite" } }, "osProfile": { "computerName": "[concat(parameters('virtualMachineNamePrefix'),copyIndex(1))]", "adminUsername": "[parameters('virtualMachineAdminUserName')]", "windowsConfiguration": { "provisionVMAgent": true }, "secrets": [], "adminPassword": "[parameters('virtualMachineAdminPassword')]" }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces', concat(parameters('virtualMachineNamePrefix'), copyIndex(1), '-NIC1'))]" } ] }, "availabilitySet": { "id": "[resourceId('Microsoft.Compute/availabilitySets', parameters('availabilitySetName'))]" }, "diagnosticsProfile": { "bootDiagnostics": { "enabled": true, "storageUri": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('diagnosticStorageAccountName')), '2016-01-01').primaryEndpoints.blob]" } } }, "dependsOn": [ "[concat('Microsoft.Compute/availabilitySets/', parameters('availabilitySetName'))]", "[concat('Microsoft.Storage/storageAccounts/', variables('diagnosticStorageAccountName'))]", "[resourceId('Microsoft.Network/networkInterfaces', concat(parameters('virtualMachineNamePrefix'), copyIndex(1), '-NIC1'))]" ] }, { "type": "Microsoft.Network/networkInterfaces", "name": "[concat(parameters('virtualMachineNamePrefix'), copyIndex(1), '-NIC1')]", "apiVersion": "2016-03-30", "location": "[parameters('location')]", "copy": { "name": "NICCopy", "count": "[parameters('virtualMachineCount')]" }, "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Dynamic", "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses', concat(parameters('virtualMachineNamePrefix'), copyIndex(1), '-PIP1'))]" }, "subnet": { "id": "[variables('subnetRef')]" } } } ], "dnsSettings": { "dnsServers": [] }, "enableIPForwarding": false }, "dependsOn": [ "[resourceId('Microsoft.Network/publicIPAddresses', concat(parameters('virtualMachineNamePrefix'), copyIndex(1), '-PIP1'))]", "[resourceId('Microsoft.Network/virtualNetworks/', variables('myVNETName'))]" ] }, { "apiVersion": "2016-03-30", "type": "Microsoft.Network/publicIPAddresses", "name": "[concat(parameters('virtualMachineNamePrefix'), copyIndex(1), '-PIP1')]", "location": "[parameters('location')]", "copy": { "name": "PIPCopy", "count": "[parameters('virtualMachineCount')]" }, "tags": { "displayName": "[concat(parameters('virtualMachineNamePrefix'), copyIndex(1), '-PIP1')]" }, "properties": { "publicIPAllocationMethod": "Dynamic", "dnsSettings": { "domainNameLabel": "[concat(parameters('dnsPrefixForPublicIP'), copyIndex(1))]" } } } ], "outputs": {} } ================================================ FILE: templates/AZ-300/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { } } ================================================ FILE: templates/Basic-ACR-AKS-Blueprint/Artifacts/16985fcd-e84e-4310-8306-45c89bccc429.json ================================================ { "kind": "roleAssignment", "properties": { "displayName": "[User group or application name] : Contributor", "dependsOn": [], "roleDefinitionId": "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c", "principalIds": "[parameters('[Usergrouporapplicationname]:Contributor_RoleAssignmentName')]", "resourceGroup": "ResourceGroup" } } ================================================ FILE: templates/Basic-ACR-AKS-Blueprint/Artifacts/31e3b372-1efb-42e8-ac45-d938d00212d6.json ================================================ { "kind": "roleAssignment", "properties": { "displayName": "[User group or application name] : AcrPull", "dependsOn": [], "roleDefinitionId": "/providers/Microsoft.Authorization/roleDefinitions/7f951dda-4ed3-4680-a7ca-43fe172d538d", "principalIds": "[parameters('[Usergrouporapplicationname]:AcrPull_RoleAssignmentName')]", "resourceGroup": "ResourceGroup" } } ================================================ FILE: templates/Basic-ACR-AKS-Blueprint/Artifacts/397ca67f-80f5-4da5-9484-f71ce2f58030.json ================================================ { "kind": "roleAssignment", "properties": { "displayName": "[User group or application name] : AcrDelete", "dependsOn": [], "roleDefinitionId": "/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11", "principalIds": "[parameters('[Usergrouporapplicationname]:AcrDelete_RoleAssignmentName')]", "resourceGroup": "ResourceGroup" } } ================================================ FILE: templates/Basic-ACR-AKS-Blueprint/Artifacts/a369d0c9-ab75-42b2-8677-2adb34f2757c.json ================================================ { "kind": "policyAssignment", "properties": { "displayName": "Kubernetes cluster pod security baseline standards for Linux-based workloads", "dependsOn": [], "policyDefinitionId": "/providers/Microsoft.Authorization/policySetDefinitions/a8640138-9b0a-4a28-b8cb-1666c838647d", "parameters": { "effect": { "value": "[parameters('kubernetesclusterpodsecuritybaselinestandardsforLinux-basedworkloads_effect')]" }, "excludedNamespaces": { "value": "[parameters('kubernetesclusterpodsecuritybaselinestandardsforLinux-basedworkloads_excludedNamespaces')]" }, "namespaces": { "value": "[parameters('kubernetesclusterpodsecuritybaselinestandardsforLinux-basedworkloads_namespaces')]" } }, "resourceGroup": "ResourceGroup" } } ================================================ FILE: templates/Basic-ACR-AKS-Blueprint/Artifacts/d8a78686-485d-4956-96a6-64f305a7f822.json ================================================ { "kind": "template", "properties": { "displayName": "aks.json", "description": "", "dependsOn": [], "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "aksClusterName": { "type": "string", "defaultValue": "aks101cluster-vmss", "metadata": { "description": "The name of the Managed Cluster resource." } }, "location": { "defaultValue": "[resourceGroup().location]", "type": "string", "metadata": { "description": "The location of AKS resource." } }, "dnsPrefix": { "type": "string", "metadata": { "description": "Optional DNS prefix to use with hosted Kubernetes API server FQDN." } }, "osDiskSizeGB": { "type": "int", "defaultValue": 0, "metadata": { "description": "Disk size (in GiB) to provision for each of the agent pool nodes. This value ranges from 0 to 1023. Specifying 0 will apply the default disk size for that agentVMSize." }, "minValue": 0, "maxValue": 1023 }, "agentCount": { "type": "int", "defaultValue": 3, "metadata": { "description": "The number of nodes for the cluster. 1 Node is enough for Dev/Test and minimum 3 nodes, is recommended for Production" }, "minValue": 1, "maxValue": 100 }, "agentVMSize": { "type": "string", "defaultValue": "Standard_D2s_v3", "metadata": { "description": "The size of the Virtual Machine." } }, "osType": { "type": "string", "defaultValue": "Linux", "allowedValues": [ "Linux", "Windows" ], "metadata": { "description": "The type of operating system." } } }, "resources": [ { "apiVersion": "2020-07-01", "type": "Microsoft.ContainerService/managedClusters", "location": "[parameters('location')]", "name": "[parameters('aksClusterName')]", "tags": { "displayname": "AKS Cluster" }, "identity": { "type": "SystemAssigned" }, "properties": { "enableRBAC": true, "dnsPrefix": "[parameters('dnsPrefix')]", "agentPoolProfiles": [ { "name": "agentpool", "osDiskSizeGB": "[parameters('osDiskSizeGB')]", "count": "[parameters('agentCount')]", "vmSize": "[parameters('agentVMSize')]", "osType": "[parameters('osType')]", "storageProfile": "ManagedDisks", "type": "VirtualMachineScaleSets", "mode": "System" } ] } } ], "outputs": { "controlPlaneFQDN": { "type": "string", "value": "[reference(resourceId('Microsoft.ContainerService/managedClusters/', parameters('aksClusterName'))).fqdn]" } } }, "resourceGroup": "ResourceGroup", "parameters": { "aksClusterName": { "value": "[parameters('aks.json_aksClusterName')]" }, "location": { "value": "[parameters('aks.json_location')]" }, "dnsPrefix": { "value": "[parameters('aks.json_dnsPrefix')]" }, "osDiskSizeGB": { "value": "[parameters('aks.json_osDiskSizeGB')]" }, "agentCount": { "value": "[parameters('aks.json_agentCount')]" }, "agentVMSize": { "value": "[parameters('aks.json_agentVMSize')]" }, "osType": { "value": "[parameters('aks.json_osType')]" } } } } ================================================ FILE: templates/Basic-ACR-AKS-Blueprint/Artifacts/d8c28060-2804-4421-bed1-f61a5f456183.json ================================================ { "kind": "roleAssignment", "properties": { "displayName": "[User group or application name] : AcrPush", "dependsOn": [], "roleDefinitionId": "/providers/Microsoft.Authorization/roleDefinitions/8311e382-0749-4cb8-b61a-304f252e45ec", "principalIds": "[parameters('[Usergrouporapplicationname]:AcrPush_RoleAssignmentName')]", "resourceGroup": "ResourceGroup" } } ================================================ FILE: templates/Basic-ACR-AKS-Blueprint/Artifacts/f465a2a1-0e85-439b-a9ac-3dcf94e066cf.json ================================================ { "kind": "template", "properties": { "displayName": "acr.json", "description": "", "dependsOn": [], "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.4.1.14562", "templateHash": "17444016317697675404" } }, "parameters": { "acrName": { "type": "string", "metadata": { "description": "Name of the azure container registry (must be globally unique)" }, "maxLength": 50, "minLength": 5 }, "acrAdminUserEnabled": { "type": "bool", "defaultValue": false, "metadata": { "description": "Enable an admin user that has push/pull permission to the registry." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } }, "acrSku": { "type": "string", "defaultValue": "Basic", "metadata": { "description": "Tier of your Azure Container Registry." }, "allowedValues": [ "Basic", "Standard", "Premium" ] } }, "functions": [], "resources": [ { "type": "Microsoft.ContainerRegistry/registries", "apiVersion": "2019-12-01-preview", "name": "[parameters('acrName')]", "location": "[parameters('location')]", "tags": { "displayName": "Container Registry", "container.registry": "[parameters('acrName')]" }, "sku": { "name": "[parameters('acrSku')]" }, "properties": { "adminUserEnabled": "[parameters('acrAdminUserEnabled')]" } } ], "outputs": { "acrLoginServer": { "type": "string", "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('acrName'))).loginServer]" } } }, "resourceGroup": "ResourceGroup", "parameters": { "acrName": { "value": "[parameters('acr.json_acrName')]" }, "acrAdminUserEnabled": { "value": "[parameters('acr.json_acrAdminUserEnabled')]" }, "location": { "value": "[parameters('acr.json_location')]" }, "acrSku": { "value": "[parameters('acr.json_acrSku')]" } } } } ================================================ FILE: templates/Basic-ACR-AKS-Blueprint/Blueprint.json ================================================ { "properties": { "targetScope": "subscription", "parameters": { "aks.json_aksClusterName": { "type": "string", "metadata": { "displayName": "aksClusterName (aks.json)", "description": "The name of the Managed Cluster resource." }, "defaultValue": "aks101cluster-vmss", "allowedValues": [] }, "aks.json_location": { "type": "string", "metadata": { "displayName": "location (aks.json)", "description": "The location of AKS resource." }, "allowedValues": [] }, "aks.json_dnsPrefix": { "type": "string", "metadata": { "displayName": "dnsPrefix (aks.json)", "description": "Optional DNS prefix to use with hosted Kubernetes API server FQDN." }, "allowedValues": [] }, "aks.json_osDiskSizeGB": { "type": "int", "metadata": { "displayName": "osDiskSizeGB (aks.json)", "description": "Disk size (in GiB) to provision for each of the agent pool nodes. This value ranges from 0 to 1023. Specifying 0 will apply the default disk size for that agentVMSize." }, "defaultValue": 0, "allowedValues": [] }, "aks.json_agentCount": { "type": "int", "metadata": { "displayName": "agentCount (aks.json)", "description": "The number of nodes for the cluster. 1 Node is enough for Dev/Test and minimum 3 nodes, is recommended for Production" }, "defaultValue": 3, "allowedValues": [] }, "aks.json_agentVMSize": { "type": "string", "metadata": { "displayName": "agentVMSize (aks.json)", "description": "The size of the Virtual Machine." }, "defaultValue": "Standard_D2s_v3", "allowedValues": [] }, "aks.json_osType": { "type": "string", "metadata": { "displayName": "osType (aks.json)", "description": "The type of operating system." }, "defaultValue": "Linux", "allowedValues": [ "Linux", "Windows" ] }, "acr.json_acrName": { "type": "string", "metadata": { "displayName": "acrName (acr.json)", "description": "Name of the azure container registry (must be globally unique)" }, "allowedValues": [] }, "acr.json_acrAdminUserEnabled": { "type": "bool", "metadata": { "displayName": "acrAdminUserEnabled (acr.json)", "description": "Enable an admin user that has push/pull permission to the registry." }, "defaultValue": false, "allowedValues": [] }, "acr.json_location": { "type": "string", "metadata": { "displayName": "location (acr.json)", "description": "Location for all resources." }, "allowedValues": [] }, "acr.json_acrSku": { "type": "string", "metadata": { "displayName": "acrSku (acr.json)", "description": "Tier of your Azure Container Registry." }, "defaultValue": "Basic", "allowedValues": [ "Basic", "Standard", "Premium" ] }, "kubernetesclusterpodsecuritybaselinestandardsforLinux-basedworkloads_effect": { "type": "string", "metadata": { "displayName": "Effect (Policy: Kubernetes cluster pod security baseline standards for Linux-based workloads)" }, "defaultValue": "audit", "allowedValues": [ "audit", "deny", "disabled" ] }, "kubernetesclusterpodsecuritybaselinestandardsforLinux-basedworkloads_excludedNamespaces": { "type": "array", "metadata": { "displayName": "Namespace exclusions (Policy: Kubernetes cluster pod security baseline standards for Linux-based workloads)" }, "defaultValue": [ "kube-system", "gatekeeper-system", "azure-arc" ], "allowedValues": [] }, "kubernetesclusterpodsecuritybaselinestandardsforLinux-basedworkloads_namespaces": { "type": "array", "metadata": { "displayName": "Namespace inclusions (Policy: Kubernetes cluster pod security baseline standards for Linux-based workloads)" }, "defaultValue": [], "allowedValues": [] }, "[Usergrouporapplicationname]:Contributor_RoleAssignmentName": { "type": "array", "metadata": { "displayName": "[User group or application name] ([User group or application name] : Contributor)", "strongType": "PrincipalId" } }, "[Usergrouporapplicationname]:AcrPull_RoleAssignmentName": { "type": "array", "metadata": { "displayName": "[User group or application name] ([User group or application name] : AcrPull)", "strongType": "PrincipalId" } }, "[Usergrouporapplicationname]:AcrPush_RoleAssignmentName": { "type": "array", "metadata": { "displayName": "[User group or application name] ([User group or application name] : AcrPush)", "strongType": "PrincipalId" } }, "[Usergrouporapplicationname]:AcrDelete_RoleAssignmentName": { "type": "array", "metadata": { "displayName": "[User group or application name] ([User group or application name] : AcrDelete)", "strongType": "PrincipalId" } } }, "resourceGroups": { "ResourceGroup": { "dependsOn": [], "tags": { "class": "az500" } } } } } ================================================ FILE: templates/active-directory-new-domain-ha-2-dc/.gitignore ================================================ azuredeploy.parameters.local.json ================================================ FILE: templates/active-directory-new-domain-ha-2-dc/DSC/ConfigureADBDC.ps1 ================================================ configuration ConfigureADBDC { param ( [Parameter(Mandatory)] [String]$DomainName, [Parameter(Mandatory)] [System.Management.Automation.PSCredential]$Admincreds, [Int]$RetryCount=20, [Int]$RetryIntervalSec=30 ) Import-DscResource -ModuleName xActiveDirectory, xPendingReboot [System.Management.Automation.PSCredential ]$DomainCreds = New-Object System.Management.Automation.PSCredential ("${DomainName}\$($Admincreds.UserName)", $Admincreds.Password) Node localhost { LocalConfigurationManager { RebootNodeIfNeeded = $true } xWaitForADDomain DscForestWait { DomainName = $DomainName DomainUserCredential= $DomainCreds RetryCount = $RetryCount RetryIntervalSec = $RetryIntervalSec } xADDomainController BDC { DomainName = $DomainName DomainAdministratorCredential = $DomainCreds SafemodeAdministratorPassword = $DomainCreds DatabasePath = "F:\NTDS" LogPath = "F:\NTDS" SysvolPath = "F:\SYSVOL" DependsOn = "[xWaitForADDomain]DscForestWait" } <# Script UpdateDNSForwarder { SetScript = { Write-Verbose -Verbose "Getting DNS forwarding rule..." $dnsFwdRule = Get-DnsServerForwarder -Verbose if ($dnsFwdRule) { Write-Verbose -Verbose "Removing DNS forwarding rule" Remove-DnsServerForwarder -IPAddress $dnsFwdRule.IPAddress -Force -Verbose } Write-Verbose -Verbose "End of UpdateDNSForwarder script..." } GetScript = { @{} } TestScript = { $false} DependsOn = "[xADDomainController]BDC" } #> xPendingReboot RebootAfterPromotion { Name = "RebootAfterDCPromotion" DependsOn = "[xADDomainController]BDC" } } } ================================================ FILE: templates/active-directory-new-domain-ha-2-dc/DSC/CreateADPDC.ps1 ================================================ configuration CreateADPDC { param ( [Parameter(Mandatory)] [String]$DomainName, [Parameter(Mandatory)] [System.Management.Automation.PSCredential]$Admincreds, [Int]$RetryCount=20, [Int]$RetryIntervalSec=30 ) Import-DscResource -ModuleName xActiveDirectory, xStorage, xNetworking, PSDesiredStateConfiguration, xPendingReboot [System.Management.Automation.PSCredential ]$DomainCreds = New-Object System.Management.Automation.PSCredential ("${DomainName}\$($Admincreds.UserName)", $Admincreds.Password) $Interface=Get-NetAdapter|Where Name -Like "Ethernet*"|Select-Object -First 1 $InterfaceAlias=$($Interface.Name) Node localhost { LocalConfigurationManager { RebootNodeIfNeeded = $true } WindowsFeature DNS { Ensure = "Present" Name = "DNS" } Script EnableDNSDiags { SetScript = { Set-DnsServerDiagnostics -All $true Write-Verbose -Verbose "Enabling DNS client diagnostics" } GetScript = { @{} } TestScript = { $false } DependsOn = "[WindowsFeature]DNS" } WindowsFeature DnsTools { Ensure = "Present" Name = "RSAT-DNS-Server" DependsOn = "[WindowsFeature]DNS" } xDnsServerAddress DnsServerAddress { Address = '127.0.0.1' InterfaceAlias = $InterfaceAlias AddressFamily = 'IPv4' DependsOn = "[WindowsFeature]DNS" } xWaitforDisk Disk2 { DiskNumber = 2 RetryIntervalSec =$RetryIntervalSec RetryCount = $RetryCount } xDisk ADDataDisk { DiskNumber = 2 DriveLetter = "F" DependsOn = "[xWaitForDisk]Disk2" } WindowsFeature ADDSInstall { Ensure = "Present" Name = "AD-Domain-Services" DependsOn="[WindowsFeature]DNS" } WindowsFeature ADDSTools { Ensure = "Present" Name = "RSAT-ADDS-Tools" DependsOn = "[WindowsFeature]ADDSInstall" } WindowsFeature ADAdminCenter { Ensure = "Present" Name = "RSAT-AD-AdminCenter" DependsOn = "[WindowsFeature]ADDSTools" } xADDomain FirstDS { DomainName = $DomainName DomainAdministratorCredential = $DomainCreds SafemodeAdministratorPassword = $DomainCreds DatabasePath = "F:\NTDS" LogPath = "F:\NTDS" SysvolPath = "F:\SYSVOL" DependsOn = @("[WindowsFeature]ADDSInstall", "[xDisk]ADDataDisk") } xPendingReboot RebootAfterPromotion{ Name = "RebootAfterPromotion" DependsOn = "[xADDomain]FirstDS" } } } ================================================ FILE: templates/active-directory-new-domain-ha-2-dc/DSC/PrepareADBDC.ps1 ================================================ configuration PrepareADBDC { param ( [Parameter(Mandatory)] [String]$DNSServer, [Int]$RetryCount=20, [Int]$RetryIntervalSec=30 ) Import-DscResource -ModuleName xStorage, xNetworking $Interface=Get-NetAdapter|Where Name -Like "Ethernet*"|Select-Object -First 1 $InterfaceAlias=$($Interface.Name) Node localhost { LocalConfigurationManager { RebootNodeIfNeeded = $true } xWaitforDisk Disk2 { DiskNumber = 2 RetryIntervalSec =$RetryIntervalSec RetryCount = $RetryCount } xDisk ADDataDisk { DiskNumber = 2 DriveLetter = "F" DependsOn = "[xWaitForDisk]Disk2" } WindowsFeature ADDSInstall { Ensure = "Present" Name = "AD-Domain-Services" } WindowsFeature ADDSTools { Ensure = "Present" Name = "RSAT-ADDS-Tools" DependsOn = "[WindowsFeature]ADDSInstall" } WindowsFeature ADAdminCenter { Ensure = "Present" Name = "RSAT-AD-AdminCenter" DependsOn = "[WindowsFeature]ADDSTools" } xDnsServerAddress DnsServerAddress { Address = $DNSServer InterfaceAlias = $InterfaceAlias AddressFamily = 'IPv4' DependsOn="[WindowsFeature]ADDSInstall" } } } ================================================ FILE: templates/active-directory-new-domain-ha-2-dc/README.md ================================================ # Create 2 new Windows VMs, create a new AD Forest, Domain and 2 DCs in an availability set This template will deploy 2 new VMs (along with a new VNet and Load Balancer) and create a new AD forest and domain, each VM will be created as a DC for the new domain and will be placed in an availability set. Each VM will also have an RDP endpoint added with a public load balanced IP address. Click the button below to deploy # Known Issues + This template is entirely serial due to some concurrency issues between the platform agent and the DSC extension which cause problems when multiple VM and\or extension resources are deployed concurrently, this will be fixed in the near future ================================================ FILE: templates/active-directory-new-domain-ha-2-dc/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "type": "string", "metadata": { "description": "The name of the Administrator of the new VM and Domain" }, "defaultValue": "adAdministrator" }, "adminPassword": { "type": "securestring", "metadata": { "description": "The password for the Administrator account of the new VM and Domain" } }, "domainName": { "type": "string", "metadata": { "description": "The FQDN of the AD Domain created " } }, "dnsPrefix": { "type": "string", "metadata": { "description": "The DNS prefix for the public IP address used by the Load Balancer" } }, "pdcRDPPort": { "type": "int", "metadata": { "description": "The public RDP port for the PDC VM" }, "defaultValue": 3389 }, "bdcRDPPort": { "type": "int", "metadata": { "description": "The public RDP port for the BDC VM" }, "defaultValue": 13389 }, "_artifactsLocation": { "type": "string", "metadata": { "description": "The location of resources, such as templates and DSC modules, that the template depends on" }, "defaultValue": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/active-directory-new-domain-ha-2-dc" }, "_artifactsLocationSasToken": { "type": "securestring", "metadata": { "description": "Auto-generated token to access _artifactsLocation" }, "defaultValue": "" }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } } }, "variables": { "storageAccountType": "Premium_LRS", "adPDCVMName": "adPDC", "adBDCVMName": "adBDC", "imagePublisher": "MicrosoftWindowsServer", "imageOffer": "WindowsServer", "imageSKU": "2016-Datacenter", "adAvailabilitySetName": "adAvailabiltySet", "publicIPAddressName": "ad-lb-pip", "adVMSize": "Standard_DS2_v2", "adLBFE": "LBFE", "adLBBE": "LBBE", "adPDCRDPNAT": "adPDCRDP", "adBDCRDPNAT": "adBDCRDP", "virtualNetworkName": "adVNET", "virtualNetworkAddressRange": "10.0.0.0/16", "adSubnetName": "adSubnet", "adSubnet": "10.0.0.0/24", "adPDCNicName": "adPDCNic", "adPDCNicIPAddress": "10.0.0.4", "adBDCNicName": "adBDCNic", "adBDCNicIPAddress": "10.0.0.5", "adSubnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), variables('adSubnetName'))]", "adLBName": "adLoadBalancer", "adlbID": "[resourceId('Microsoft.Network/loadBalancers',variables('adLBName'))]", "adlbFEConfigID": "[concat(variables('adlbID'),'/frontendIPConfigurations/',variables('adLBFE'))]", "adPDCRDPNATRuleID": "[concat(variables('adlbID'),'/inboundNatRules/',variables('adPDCRDPNAT'))]", "adBDCRDPNATRuleID": "[concat(variables('adlbID'),'/inboundNatRules/',variables('adBDCRDPNAT'))]", "adBEAddressPoolID": "[concat(variables('adlbID'),'/backendAddressPools/',variables('adLBBE'))]", "adDataDiskSize": 1000, "vnetTemplateUri": "[concat(parameters('_artifactsLocation'),'/nestedtemplates/vnet.json', parameters('_artifactsLocationSasToken'))]", "nicTemplateUri": "[concat(parameters('_artifactsLocation'),'/nestedtemplates/nic.json', parameters('_artifactsLocationSasToken'))]", "vnetwithDNSTemplateUri": "[concat(parameters('_artifactsLocation'),'/nestedtemplates/vnet-with-dns-server.json', parameters('_artifactsLocationSasToken'))]", "configureADBDCTemplateUri": "[concat(parameters('_artifactsLocation'),'/nestedtemplates/configureADBDC.json', parameters('_artifactsLocationSasToken'))]", "adPDCModulesURL": "[concat(parameters('_artifactsLocation'),'/DSC/CreateADPDC.zip', parameters('_artifactsLocationSasToken'))]", "adPDCConfigurationFunction": "CreateADPDC.ps1\\CreateADPDC", "adBDCPreparationModulesURL": "[concat(parameters('_artifactsLocation'),'/DSC/PrepareADBDC.zip', parameters('_artifactsLocationSasToken'))]", "adBDCPreparationFunction": "PrepareADBDC.ps1\\PrepareADBDC", "adBDCConfigurationModulesURL": "[concat(parameters('_artifactsLocation'),'/DSC/ConfigureADBDC.zip', parameters('_artifactsLocationSasToken'))]", "adBDCConfigurationFunction": "ConfigureADBDC.ps1\\ConfigureADBDC" }, "resources": [ { "name": "[variables('publicIPAddressName')]", "type": "Microsoft.Network/publicIPAddresses", "apiVersion": "2016-10-01", "location": "[parameters('location')]", "properties": { "publicIPAllocationMethod": "Dynamic", "dnsSettings": { "domainNameLabel": "[parameters('dnsPrefix')]" } } }, { "apiVersion": "2017-03-30", "type": "Microsoft.Compute/availabilitySets", "location": "[parameters('location')]", "name": "[variables('adAvailabilitySetName')]", "properties": { "PlatformUpdateDomainCount": 20, "PlatformFaultDomainCount": 2 }, "sku": { "name": "Aligned" } }, { "name": "VNet", "type": "Microsoft.Resources/deployments", "apiVersion": "2016-09-01", "properties": { "mode": "Incremental", "templateLink": { "uri": "[variables('vnetTemplateUri')]", "contentVersion": "1.0.0.0" }, "parameters": { "virtualNetworkName": { "value": "[variables('virtualNetworkName')]" }, "virtualNetworkAddressRange": { "value": "[variables('virtualNetworkAddressRange')]" }, "subnetName": { "value": "[variables('adSubnetName')]" }, "subnetRange": { "value": "[variables('adSubnet')]" } } } }, { "name": "[variables('adLBName')]", "type": "Microsoft.Network/loadBalancers", "apiVersion": "2016-10-01", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]" ], "properties": { "frontendIPConfigurations": [ { "name": "[variables('adLBFE')]", "properties": { "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]" } } } ], "backendAddressPools": [ { "name": "[variables('adLBBE')]" } ], "inboundNatRules": [ { "name": "[variables('adPDCRDPNAT')]", "properties": { "frontendIPConfiguration": { "id": "[variables('adlbFEConfigID')]" }, "protocol": "Tcp", "frontendPort": "[parameters('pdcRDPPort')]", "backendPort": 3389, "enableFloatingIP": false } }, { "name": "[variables('adBDCRDPNAT')]", "properties": { "frontendIPConfiguration": { "id": "[variables('adlbFEConfigID')]" }, "protocol": "Tcp", "frontendPort": "[parameters('bdcRDPPort')]", "backendPort": 3389, "enableFloatingIP": false } } ] } }, { "name": "[variables('adPDCNicName')]", "type": "Microsoft.Network/networkInterfaces", "apiVersion": "2016-10-01", "location": "[parameters('location')]", "dependsOn": [ "Microsoft.Resources/deployments/VNet", "[variables('adLBName')]" ], "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Static", "privateIPAddress": "[variables('adPDCNicIPAddress')]", "subnet": { "id": "[variables('adSubnetRef')]" }, "loadBalancerBackendAddressPools": [ { "id": "[variables('adBEAddressPoolID')]" } ], "loadBalancerInboundNatRules": [ { "id": "[variables('adPDCRDPNATRuleID')]" } ] } } ] } }, { "name": "[variables('adBDCNicName')]", "type": "Microsoft.Network/networkInterfaces", "apiVersion": "2016-10-01", "location": "[parameters('location')]", "dependsOn": [ "Microsoft.Resources/deployments/VNet", "[concat('Microsoft.Network/loadBalancers/',variables('adLBName'))]" ], "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Static", "privateIPAddress": "[variables('adBDCNicIPAddress')]", "subnet": { "id": "[variables('adSubnetRef')]" }, "loadBalancerBackendAddressPools": [ { "id": "[variables('adBEAddressPoolID')]" } ], "loadBalancerInboundNatRules": [ { "id": "[variables('adBDCRDPNATRuleID')]" } ] } } ] } }, { "name": "[variables('adPDCVMName')]", "type": "Microsoft.Compute/virtualMachines", "apiVersion": "2017-03-30", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/networkInterfaces',variables('adPDCNicName'))]", "[resourceId('Microsoft.Compute/availabilitySets', variables('adAvailabilitySetName'))]", "[resourceId('Microsoft.Network/loadBalancers',variables('adLBName'))]" ], "properties": { "hardwareProfile": { "vmSize": "[variables('adVMSize')]" }, "availabilitySet": { "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('adAvailabilitySetName'))]" }, "osProfile": { "computerName": "[variables('adPDCVMName')]", "adminUsername": "[parameters('adminUsername')]", "adminPassword": "[parameters('adminPassword')]" }, "storageProfile": { "imageReference": { "publisher": "[variables('imagePublisher')]", "offer": "[variables('imageOffer')]", "sku": "[variables('imageSKU')]", "version": "latest" }, "osDisk": { "name": "[concat(variables('adPDCVMName'),'_OSDisk')]", "caching": "ReadWrite", "createOption": "FromImage", "managedDisk": { "storageAccountType": "[variables('storageAccountType')]" } }, "dataDisks": [ { "name": "[concat(variables('adPDCVMName'),'_data-disk1')]", "caching": "None", "diskSizeGB": "[variables('adDataDiskSize')]", "lun": 0, "createOption": "Empty", "managedDisk": { "storageAccountType": "[variables('storageAccountType')]" } } ] }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('adPDCNicName'))]" } ] } }, "resources": [ { "name": "CreateADForest", "type": "extensions", "apiVersion": "2016-03-30", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Compute/virtualMachines', variables('adPDCVMName'))]" ], "properties": { "publisher": "Microsoft.Powershell", "type": "DSC", "typeHandlerVersion": "2.19", "autoUpgradeMinorVersion": true, "settings": { "ModulesUrl": "[variables('adPDCModulesURL')]", "ConfigurationFunction": "[variables('adPDCConfigurationFunction')]", "Properties": { "DomainName": "[parameters('domainName')]", "AdminCreds": { "UserName": "[parameters('adminUsername')]", "Password": "PrivateSettingsRef:AdminPassword" } } }, "protectedSettings": { "Items": { "AdminPassword": "[parameters('adminPassword')]" } } } } ] }, { "name": "UpdateVNetDNS1", "type": "Microsoft.Resources/deployments", "apiVersion": "2016-09-01", "dependsOn": [ "[concat('Microsoft.Compute/virtualMachines/', variables('adPDCVMName'),'/extensions/CreateADForest')]" ], "properties": { "mode": "Incremental", "templateLink": { "uri": "[variables('vnetwithDNSTemplateUri')]", "contentVersion": "1.0.0.0" }, "parameters": { "virtualNetworkName": { "value": "[variables('virtualNetworkName')]" }, "virtualNetworkAddressRange": { "value": "[variables('virtualNetworkAddressRange')]" }, "subnetName": { "value": "[variables('adSubnetName')]" }, "subnetRange": { "value": "[variables('adSubnet')]" }, "DNSServerAddress": { "value": [ "[variables('adPDCNicIPAddress')]" ] } } } }, { "name": "UpdateBDCNIC", "type": "Microsoft.Resources/deployments", "apiVersion": "2015-01-01", "dependsOn": [ "[concat('Microsoft.Network/networkInterfaces/',variables('adBDCNicName'))]", "Microsoft.Resources/deployments/UpdateVNetDNS1" ], "properties": { "mode": "Incremental", "templateLink": { "uri": "[variables('nicTemplateUri')]", "contentVersion": "1.0.0.0" }, "parameters": { "nicName": { "value": "[variables('adBDCNicName')]" }, "ipConfigurations": { "value": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Static", "privateIPAddress": "[variables('adBDCNicIPAddress')]", "subnet": { "id": "[variables('adSubnetRef')]" }, "loadBalancerBackendAddressPools": [ { "id": "[variables('adBEAddressPoolID')]" } ], "loadBalancerInboundNatRules": [ { "id": "[variables('adBDCRDPNATRuleID')]" } ] } } ] }, "dnsServers": { "value": [ "[variables('adPDCNicIPAddress')]" ] } } } }, { "name": "[variables('adBDCVMName')]", "type": "Microsoft.Compute/virtualMachines", "apiVersion": "2017-03-30", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/networkInterfaces',variables('adBDCNicName'))]", "[resourceId('Microsoft.Compute/availabilitySets', variables('adAvailabilitySetName'))]", "[resourceId('Microsoft.Network/loadBalancers',variables('adLBName'))]" ], "properties": { "hardwareProfile": { "vmSize": "[variables('adVMSize')]" }, "availabilitySet": { "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('adAvailabilitySetName'))]" }, "osProfile": { "computerName": "[variables('adBDCVMName')]", "adminUsername": "[parameters('adminUsername')]", "adminPassword": "[parameters('adminPassword')]" }, "storageProfile": { "imageReference": { "publisher": "[variables('imagePublisher')]", "offer": "[variables('imageOffer')]", "sku": "[variables('imageSKU')]", "version": "latest" }, "osDisk": { "name": "[concat(variables('adBDCVMName'),'_osdisk')]", "caching": "ReadWrite", "createOption": "FromImage", "managedDisk": { "storageAccountType": "[variables('storageAccountType')]" } }, "dataDisks": [ { "name": "[concat(variables('adBDCVMName'),'_data-disk1')]", "caching": "None", "diskSizeGB": "[variables('adDataDiskSize')]", "lun": 0, "createOption": "Empty", "managedDisk": { "storageAccountType": "[variables('storageAccountType')]" } } ] }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('adBDCNicName'))]" } ] } } }, { "type": "Microsoft.Compute/virtualMachines/extensions", "name": "[concat(variables('adBDCVMName'),'/PrepareBDC')]", "apiVersion": "2016-03-30", "location": "[parameters('location')]", "dependsOn": [ "[concat('Microsoft.Compute/virtualMachines/', variables('adBDCVMName'))]" ], "properties": { "publisher": "Microsoft.Powershell", "type": "DSC", "typeHandlerVersion": "2.19", "autoUpgradeMinorVersion": true, "settings": { "ModulesUrl": "[variables('adBDCPreparationModulesURL')]", "ConfigurationFunction": "[variables('adBDCPreparationFunction')]", "Properties": { "DNSServer": "[variables('adPDCNicIPAddress')]" } } } }, { "name": "ConfiguringBackupADDomainController", "type": "Microsoft.Resources/deployments", "apiVersion": "2016-09-01", "dependsOn": [ "[concat('Microsoft.Compute/virtualMachines/',variables('adBDCVMName'),'/extensions/PrepareBDC')]", "Microsoft.Resources/deployments/UpdateBDCNIC" ], "properties": { "mode": "Incremental", "templateLink": { "uri": "[variables('configureADBDCTemplateUri')]", "contentVersion": "1.0.0.0" }, "parameters": { "adBDCVMName": { "value": "[variables('adBDCVMName')]" }, "location": { "value": "[parameters('location')]" }, "adminUsername": { "value": "[parameters('adminUsername')]" }, "adminPassword": { "value": "[parameters('adminPassword')]" }, "domainName": { "value": "[parameters('domainName')]" }, "adBDCConfigurationFunction": { "value": "[variables('adBDCConfigurationFunction')]" }, "adBDCConfigurationModulesURL": { "value": "[variables('adBDCConfigurationModulesURL')]" } } } }, { "name": "UpdateVNetDNS2", "type": "Microsoft.Resources/deployments", "apiVersion": "2016-09-01", "dependsOn": [ "Microsoft.Resources/deployments/ConfiguringBackupADDomainController" ], "properties": { "mode": "Incremental", "templateLink": { "uri": "[variables('vnetwithDNSTemplateUri')]", "contentVersion": "1.0.0.0" }, "parameters": { "virtualNetworkName": { "value": "[variables('virtualNetworkName')]" }, "virtualNetworkAddressRange": { "value": "[variables('virtualNetworkAddressRange')]" }, "subnetName": { "value": "[variables('adSubnetName')]" }, "subnetRange": { "value": "[variables('adSubnet')]" }, "DNSServerAddress": { "value": [ "[variables('adPDCNicIPAddress')]", "[variables('adBDCNicIPAddress')]" ] } } } } ] } ================================================ FILE: templates/active-directory-new-domain-ha-2-dc/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "value": "GEN-UNIQUE" }, "adminPassword": { "value": "GEN-PASSWORD" }, "dnsPrefix": { "value": "GEN-UNIQUE" }, "domainName": { "value": "mydomain.local" } } } ================================================ FILE: templates/active-directory-new-domain-ha-2-dc/metadata.json ================================================ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", "itemDisplayName": "Create an new AD Domain with 2 Domain Controllers", "description": "This template creates 2 new VMs to be AD DCs (primary and backup) for a new Forest and Domain", "summary": "This template creates 2 Azure VMs with AD", "githubUsername": "simongdavies", "dateUpdated": "2018-07-05" } ================================================ FILE: templates/active-directory-new-domain-ha-2-dc/nestedtemplates/configureADBDC.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "adBDCVMName": { "type": "string" }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]" }, "adminUsername": { "type": "string" }, "adminPassword": { "type": "securestring" }, "domainName": { "type": "string" }, "adBDCConfigurationFunction": { "type": "string" }, "adBDCConfigurationModulesURL": { "type": "string" } }, "resources": [ { "type": "Microsoft.Compute/virtualMachines/extensions", "name": "[concat(parameters('adBDCVMName'),'/PrepareBDC')]", "apiVersion": "2016-03-30", "location": "[parameters('location')]", "properties": { "publisher": "Microsoft.Powershell", "type": "DSC", "typeHandlerVersion": "2.21", "autoUpgradeMinorVersion": true, "settings": { "modulesURL": "[parameters('adBDCConfigurationModulesURL')]", "wmfVersion": "4.0", "configurationFunction": "[parameters('adBDCConfigurationFunction')]", "properties": { "domainName": "[parameters('domainName')]", "adminCreds": { "userName": "[parameters('adminUsername')]", "password": "privateSettingsRef:adminPassword" } } }, "protectedSettings": { "items": { "adminPassword": "[parameters('adminPassword')]" } } } } ], "outputs": {} } ================================================ FILE: templates/active-directory-new-domain-ha-2-dc/nestedtemplates/nic.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "nicName": { "type": "string", "metadata": { "Description": "The name of the NIC to Create or Update" } }, "ipConfigurations": { "type": "array", "metadata": { "Description": "The IP configurations of the NIC" } }, "dnsServers": { "type": "array", "metadata": { "Description": "The DNS Servers of the NIC" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } } }, "resources": [ { "name": "[parameters('nicName')]", "type": "Microsoft.Network/networkInterfaces", "location": "[parameters('location')]", "apiVersion": "2016-10-01", "properties": { "ipConfigurations": "[parameters('ipConfigurations')]", "dnsSettings": { "dnsServers": "[parameters('dnsServers')]" } } } ] } ================================================ FILE: templates/active-directory-new-domain-ha-2-dc/nestedtemplates/vnet-with-dns-server.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "virtualNetworkName": { "type": "string", "metadata": { "Description": "The name of the Virtual Network to Create" } }, "virtualNetworkAddressRange": { "type": "string", "metadata": { "Description": "The address range of the new VNET in CIDR format" }, "defaultValue": "10.0.0.0/16" }, "subnetName": { "type": "string", "metadata": { "Description": "The name of the subnet created in the new VNET" } }, "subnetRange": { "type": "string", "metadata": { "Description": "The address range of the subnet created in the new VNET" }, "defaultValue": "10.0.0.0/24" }, "DNSServerAddress": { "type": "array", "metadata": { "Description": "The DNS address(es) of the DNS Server(s) used by the VNET" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } } }, "resources": [ { "name": "[parameters('virtualNetworkName')]", "type": "Microsoft.Network/virtualNetworks", "location": "[parameters('location')]", "apiVersion": "2016-10-01", "properties": { "addressSpace": { "addressPrefixes": [ "[parameters('virtualNetworkAddressRange')]" ] }, "dhcpOptions": { "dnsServers": "[parameters('DNSServerAddress')]" }, "subnets": [ { "name": "[parameters('subnetName')]", "properties": { "addressPrefix": "[parameters('subnetRange')]" } } ] } } ] } ================================================ FILE: templates/active-directory-new-domain-ha-2-dc/nestedtemplates/vnet.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "virtualNetworkName": { "type": "string", "metadata": { "Description": "The name of the Virtual Network to Create" } }, "virtualNetworkAddressRange": { "type": "string", "metadata": { "Description": "The address range of the new VNET in CIDR format" }, "defaultValue": "10.0.0.0/16" }, "subnetName": { "type": "string", "metadata": { "Description": "The name of the subnet created in the new VNET" } }, "subnetRange": { "type": "string", "metadata": { "Description": "The address range of the subnet created in the new VNET" }, "defaultValue": "10.0.0.0/24" }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } } }, "resources": [ { "name": "[parameters('virtualNetworkName')]", "type": "Microsoft.Network/virtualNetworks", "location": "[parameters('location')]", "apiVersion": "2016-10-01", "properties": { "addressSpace": { "addressPrefixes": [ "[parameters('virtualNetworkAddressRange')]" ] }, "subnets": [ { "name": "[parameters('subnetName')]", "properties": { "addressPrefix": "[parameters('subnetRange')]" } } ] } } ] } ================================================ FILE: templates/customscriptext.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "type": "string", "metadata": { "description": "Username for the Virtual Machine." } }, "adminPassword": { "type": "securestring", "minLength": 12, "metadata": { "description": "Password for the Virtual Machine." } }, "dnsLabelPrefix": { "type": "string", "defaultValue": "[toLower(concat(parameters('vmName'),'-', uniqueString(resourceGroup().id, parameters('vmName'))))]", "metadata": { "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." } }, "publicIpName": { "type": "string", "defaultValue": "myPublicIP", "metadata": { "description": "Name for the Public IP used to access the Virtual Machine." } }, "publicIPAllocationMethod": { "type": "string", "defaultValue": "Dynamic", "allowedValues": [ "Dynamic", "Static" ], "metadata": { "description": "Allocation method for the Public IP used to access the Virtual Machine." } }, "publicIpSku": { "type": "string", "defaultValue": "Basic", "allowedValues": [ "Basic", "Standard" ], "metadata": { "description": "SKU for the Public IP used to access the Virtual Machine." } }, "OSVersion": { "type": "string", "defaultValue": "2019-Datacenter", "allowedValues": [ "2008-R2-SP1", "2012-Datacenter", "2012-R2-Datacenter", "2016-Nano-Server", "2016-Datacenter-with-Containers", "2016-Datacenter", "2019-Datacenter", "2019-Datacenter-Core", "2019-Datacenter-Core-smalldisk", "2019-Datacenter-Core-with-Containers", "2019-Datacenter-Core-with-Containers-smalldisk", "2019-Datacenter-smalldisk", "2019-Datacenter-with-Containers", "2019-Datacenter-with-Containers-smalldisk" ], "metadata": { "description": "The Windows version for the VM. This will pick a fully patched image of this given Windows version." } }, "vmSize": { "type": "string", "defaultValue": "Standard_D2_v3", "metadata": { "description": "Size of the virtual machine." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } }, "vmName": { "type": "string", "defaultValue": "simple-vm", "metadata": { "description": "Name of the virtual machine." } } }, "variables": { "storageAccountName": "[concat('bootdiags', uniquestring(resourceGroup().id))]", "nicName": "myVMNic", "addressPrefix": "10.0.0.0/16", "subnetName": "Subnet", "subnetPrefix": "10.0.0.0/24", "virtualNetworkName": "MyVNET", "subnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), variables('subnetName'))]", "networkSecurityGroupName": "default-NSG" }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2019-06-01", "name": "[variables('storageAccountName')]", "location": "[parameters('location')]", "sku": { "name": "Standard_LRS" }, "kind": "Storage", "properties": {} }, { "type": "Microsoft.Network/publicIPAddresses", "apiVersion": "2020-06-01", "name": "[parameters('publicIPName')]", "location": "[parameters('location')]", "sku": { "name": "[parameters('publicIpSku')]" }, "properties": { "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", "dnsSettings": { "domainNameLabel": "[parameters('dnsLabelPrefix')]" } } }, { "type": "Microsoft.Network/networkSecurityGroups", "apiVersion": "2020-06-01", "name": "[variables('networkSecurityGroupName')]", "location": "[parameters('location')]", "properties": { "securityRules": [ { "name": "default-allow-3389", "properties": { "priority": 1000, "access": "Allow", "direction": "Inbound", "destinationPortRange": "3389", "protocol": "Tcp", "sourcePortRange": "*", "sourceAddressPrefix": "*", "destinationAddressPrefix": "*" } }, { "name": "AllowHTTPInBound", "properties": { "priority": 1010, "access": "Allow", "direction": "Inbound", "destinationPortRange": "80", "protocol": "Tcp", "sourcePortRange": "*", "sourceAddressPrefix": "*", "destinationAddressPrefix": "*" } } ] } }, { "type": "Microsoft.Network/virtualNetworks", "apiVersion": "2020-06-01", "name": "[variables('virtualNetworkName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" ], "properties": { "addressSpace": { "addressPrefixes": [ "[variables('addressPrefix')]" ] }, "subnets": [ { "name": "[variables('subnetName')]", "properties": { "addressPrefix": "[variables('subnetPrefix')]", "networkSecurityGroup": { "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" } } } ] } }, { "type": "Microsoft.Compute/virtualMachines/extensions", "apiVersion": "2019-12-01", "name": "[concat(parameters('vmName'),'/', 'InstallWebServer')]", "location": "[parameters('location')]", "dependsOn": [ "[concat('Microsoft.Compute/virtualMachines/',parameters('vmName'))]" ], "properties": { "publisher": "Microsoft.Compute", "type": "CustomScriptExtension", "typeHandlerVersion": "1.7", "autoUpgradeMinorVersion": true, "settings": { "fileUris": [ "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/tutorial-vm-extension/installWebServer.ps1" ], "commandToExecute": "powershell.exe -ExecutionPolicy Unrestricted -File installWebServer.ps1" }, { "type": "Microsoft.Network/networkInterfaces", "apiVersion": "2020-06-01", "name": "[variables('nicName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPName'))]", "[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" ], "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Dynamic", "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPName'))]" }, "subnet": { "id": "[variables('subnetRef')]" } } } ] } }, { "type": "Microsoft.Compute/virtualMachines", "apiVersion": "2020-06-01", "name": "[parameters('vmName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" ], "properties": { "hardwareProfile": { "vmSize": "[parameters('vmSize')]" }, "osProfile": { "computerName": "[parameters('vmName')]", "adminUsername": "[parameters('adminUsername')]", "adminPassword": "[parameters('adminPassword')]" }, "storageProfile": { "imageReference": { "publisher": "MicrosoftWindowsServer", "offer": "WindowsServer", "sku": "[parameters('OSVersion')]", "version": "latest" }, "osDisk": { "createOption": "FromImage", "managedDisk": { "storageAccountType": "StandardSSD_LRS" } }, "dataDisks": [ { "diskSizeGB": 1023, "lun": 0, "createOption": "Empty" } ] }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" } ] }, "diagnosticsProfile": { "bootDiagnostics": { "enabled": true, "storageUri": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))).primaryEndpoints.blob]" } } } } ], "outputs": { "hostname": { "type": "string", "value": "[reference(parameters('publicIPName')).dnsSettings.fqdn]" } } } ================================================ FILE: templates/customscriptext.param.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "value": "tim" }, "adminPassword": { "reference": { "keyVault": { "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/TIM/providers/Microsoft.KeyVault/vaults/tim-keyvault-001" }, "secretName": "vmpassword5" } }, "dnsLabelPrefix": { "value": "csaz500pip01" } } } ================================================ FILE: templates/docker-containers.azcli ================================================ # ACR Trust # Create a container registry az acr create --resource-group az500-rg --name twaz500acr --sku Standard # Sign into the registry az acr login --name twaz500acr # Pull and push an image docker pull mcr.microsoft.com/hello-world docker tag mcr.microsoft.com/hello-world twaz500acr/hello-world:unsigned docker push twaz500acr/hello-world:unsigned # List images az acr repository list --name twaz500acr --output table # Run image from registry docker run twaz500acr/hello-world:unsigned # Trusted image setup (enable content trust in ACR) # Enable content trust az acr config content-trust update -r twaz500acr.azurecr.io --status Enabled docker build --disable-content-trust=false -t twaz500acr.azurecr.io/myimage:v1 . export DOCKER_CONTENT_TRUST=1 # Grant signing permissions az role assignment create --scope --role AcrImageSigner --assignee # MS Defender for Cloud for vulnerability scanning docker trust inspect --pretty example/trust-demo docker trust sign example/trust-demo:v2 docker push registrydavid.azurecr.io/hello-world:signed ================================================ FILE: templates/generative-ai/azurecli.azcli ================================================ ================================================ FILE: templates/generative-ai/azuredeploy.json ================================================ ================================================ FILE: templates/generative-ai/kusto.kql ================================================ ================================================ FILE: templates/generative-ai/main.bicep ================================================ ================================================ FILE: templates/generative-ai/powershell.ps1 ================================================ ================================================ FILE: templates/virtual-network/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "vnetName": { "type": "string", "metadata": { "description": "VNet name" } }, "vnetAddressPrefix": { "type": "string", "metadata": { "description": "Address prefix" } }, "subnet1Prefix": { "type": "string", "metadata": { "description": "Subnet 1 Prefix" } }, "subnet1Name": { "type": "string", "metadata": { "description": "Subnet 1 Name" } }, "subnet2Prefix": { "type": "string", "metadata": { "description": "Subnet 2 Prefix" } }, "subnet2Name": { "type": "string", "metadata": { "description": "Subnet 2 Name" } }, "subnet3Prefix": { "type": "string", "metadata": { "description": "Subnet 3 Prefix" } }, "subnet3Name": { "type": "string", "metadata": { "description": "Subnet 3 Name" } }, "subnet4Prefix": { "type": "string", "metadata": { "description": "Subnet 4 Prefix" } }, "subnet4Name": { "type": "string", "metadata": { "description": "Subnet 4 Name" } }, "subnet5Prefix": { "type": "string", "metadata": { "description": "Subnet 5 Prefix" } }, "subnet5Name": { "type": "string", "metadata": { "description": "Subnet 5 Name" } }, "subnet6Prefix": { "type": "string", "metadata": { "description": "Subnet 6 Prefix" } }, "subnet6Name": { "type": "string", "metadata": { "description": "Subnet 6 Name" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } } }, "variables": {}, "resources": [ { "type": "Microsoft.Network/virtualNetworks", "apiVersion": "2020-05-01", "name": "[parameters('vnetName')]", "location": "[parameters('location')]", "properties": { "addressSpace": { "addressPrefixes": [ "[parameters('vnetAddressPrefix')]" ] } }, "resources": [ { "type": "subnets", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "name": "[parameters('subnet1Name')]", "dependsOn": [ "[parameters('vnetName')]" ], "properties": { "addressPrefix": "[parameters('subnet1Prefix')]" } }, { "type": "subnets", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "name": "[parameters('subnet2Name')]", "dependsOn": [ "[parameters('vnetName')]", "[parameters('subnet1Name')]" ], "properties": { "addressPrefix": "[parameters('subnet2Prefix')]" } }, { "type": "subnets", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "name": "[parameters('subnet3Name')]", "dependsOn": [ "[parameters('vnetName')]", "[parameters('subnet2Name')]" ], "properties": { "addressPrefix": "[parameters('subnet3Prefix')]" } }, { "type": "subnets", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "name": "[parameters('subnet4Name')]", "dependsOn": [ "[parameters('vnetName')]", "[parameters('subnet3Name')]" ], "properties": { "addressPrefix": "[parameters('subnet4Prefix')]" } }, { "type": "subnets", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "name": "[parameters('subnet5Name')]", "dependsOn": [ "[parameters('vnetName')]", "[parameters('subnet4Name')]" ], "properties": { "addressPrefix": "[parameters('subnet5Prefix')]" } }, { "type": "subnets", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "name": "[parameters('subnet6Name')]", "dependsOn": [ "[parameters('vnetName')]", "[parameters('subnet5Name')]" ], "properties": { "addressPrefix": "[parameters('subnet6Prefix')]" } } ] } ] } ================================================ FILE: templates/virtual-network/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "vnetName": { "value": "hub-vnet" }, "vnetAddressPrefix": { "value": "10.10.0.0/16" }, "subnet1Prefix": { "value": "10.10.1.0/24" }, "subnet1Name": { "value": "web" }, "subnet2Prefix": { "value": "10.10.2.0/24" }, "subnet2Name": { "value": "workload" }, "subnet3Prefix": { "value": "10.10.3.0/24" }, "subnet3Name": { "value": "AzureBastionSubnet" }, "subnet4Prefix": { "value": "10.10.4.0/24" }, "subnet4Name": { "value": "AzureFirewallSubnet" }, "subnet5Prefix": { "value": "10.10.5.0/24" }, "subnet5Name": { "value": "ApplicationGatewaySubnet" }, "subnet6Prefix": { "value": "10.10.6.0/24" }, "subnet6Name": { "value": "GatewaySubnet" } } } ================================================ FILE: templates/virtual-network/hub-vnet.bicep ================================================ @description('VNet name') param vnetName string = 'spoke-vnet' @description('VNet address prefix') param vnetAddressPrefix string = '10.120.0.0/16' @description('web subnet name') param hubSubnetWebName string = 'web' @description('web subnet prefix') param hubSubnetWebPrefix string = '10.120.1.0/24' @description('hub data subnet name') param hubSubnetDataName string = 'data' @description('hub data subnet prefix') param hubSubnetDataPrefix string = '10.120.2.0/24' @description('Gateway subnet name') param gatewaySubnetName string = 'GatewaySubnet' @description('Gateway subnet prefix') param gatewaySubnetPrefix string = '10.120.3.0/24' @description('Application Gateway subnet name') param appGatewaySubnetName string = 'ApplicationGatewaySubnet' @description('Application Gateway subnet prefix') param appGatewaySubnetPrefix string = '10.120.4.0/24' @description('Bastion subnet name') param bastionSubnetName string = 'AzureBastionSubnet' @description('Bastion subnet prefix') param bastionSubnetPrefix string = '10.120.5.0/24' @description('Firewall user traffic subnet name') param firewallSubnetName string = 'AzureFirewallSubnet' @description('Firewall user traffic subnet prefix') param firewallSubnetPrefix string = '10.120.6.0/24' @description('Firewall management subnet name') param firewallMgmtSubnetName string = 'AzureFirewallManagementSubnet' @description('Firewall management subnet prefix') param firewallMgmtSubnetPrefix string = '10.120.7.0/24' resource virtualNetwork 'Microsoft.Network/virtualNetworks@2019-11-01' = { name: vnetName location: resourceGroup().location properties: { addressSpace: { addressPrefixes: [ vnetAddressPrefix ] } subnets: [ { name: hubSubnetWebName properties: { addressPrefix: hubSubnetWebPrefix } } { name: hubSubnetDataName properties: { addressPrefix: hubSubnetDataPrefix } } { name: gatewaySubnetName properties: { addressPrefix: gatewaySubnetPrefix } } { name: appGatewaySubnetName properties: { addressPrefix: appGatewaySubnetPrefix } } { name: bastionSubnetName properties: { addressPrefix: bastionSubnetPrefix } } { name: firewallSubnetName properties: { addressPrefix: firewallSubnetPrefix } } { name: firewallMgmtSubnetName properties: { addressPrefix: firewallMgmtSubnetPrefix } } ] } } ================================================ FILE: templates/virtual-network/vnets-deploy.bicep ================================================ @allowed([ 'hub' 'spoke1' 'spoke2' ]) param vNetType string module hub './hub-vnet.bicep' = if (vNetType == 'hub') { name: 'hub-vnet' params: { // override defaults here } } module spoke1 './spoke1-vnet.bicep' = if (vNetType == 'spoke1') { name: 'spoke1-vnet' params: { // override defaults here } } module spoke2 './spoke2-vnet.bicep' = if (vNetType == 'spoke2') { name: 'spoke2-vnet' params: { // override defaults here } } ================================================ FILE: templates/~arm-templates/S2S-VPN/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "enableBgp": { "type": "string", "metadata": { "description": "Enable or disable BGP" }, "defaultValue": "false", "allowedValues": [ "false" ] }, "gatewayType": { "type": "string", "metadata": { "description": "VPN or ER" }, "defaultValue": "Vpn", "allowedValues": [ "Vpn", "ER" ] }, "vpnType": { "type": "string", "metadata": { "description": "Route based or policy based" }, "defaultValue": "RouteBased", "allowedValues": [ "RouteBased", "PolicyBased" ] }, "localGatewayName": { "type": "string", "metadata": { "description": "Name for gateway connected to other VNet/on-prem network" } }, "localGatewayIpAddress": { "type": "string", "metadata": { "description": "Public IP address for the gateway to connect to (from other VNet/on-prem)" } }, "localGatewayAddressPrefix": { "type": "string", "metadata": { "description": "CIDR block for remote network" } }, "virtualNetworkName": { "type": "string", "metadata": { "description": "Name for new virtual network" } }, "addressPrefix": { "type": "string", "metadata": { "description": "Name for new virtual network" } }, "subnet1Name": { "type": "string", "defaultValue": "Subnet1", "metadata": { "description": "Name for VM subnet in the new VNet" } }, "gatewaySubnet": { "type": "string", "defaultValue": "GatewaySubnet", "metadata": { "description": "Name for gateway subnet in new VNet" }, "allowedValues": [ "GatewaySubnet" ] }, "subnet1Prefix": { "type": "string", "metadata": { "description": "CIDR block for VM subnet" } }, "gatewaySubnetPrefix": { "type": "string", "metadata": { "description": "CIDR block for gateway subnet" } }, "gatewayPublicIPName": { "type": "string", "metadata": { "description": "Name for public IP object used for the new gateway" } }, "gatewayName": { "type": "string", "metadata": { "description": "Name for the new gateway" } } }, "variables": { "gatewaySubnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets/', parameters('virtualNetworkName'),parameters('gatewaySubnet'))]" }, "resources": [ { "apiVersion": "2015-05-01-preview", "type": "Microsoft.Network/localNetworkGateways", "name": "[parameters('localGatewayName')]", "location": "[resourceGroup().location]", "properties": { "localNetworkAddressSpace": { "addressPrefixes": [ "[parameters('localGatewayAddressPrefix')]" ] }, "gatewayIpAddress": "[parameters('localGatewayIpAddress')]" } }, { "apiVersion": "2015-05-01-preview", "type": "Microsoft.Network/virtualNetworks", "name": "[parameters('virtualNetworkName')]", "location": "[resourceGroup().location]", "properties": { "addressSpace": { "addressPrefixes": [ "[parameters('addressPrefix')]" ] }, "subnets": [ { "name": "[parameters('subnet1Name')]", "properties": { "addressPrefix": "[parameters('subnet1Prefix')]" } }, { "name": "[parameters('gatewaySubnet')]", "properties": { "addressPrefix": "[parameters('gatewaySubnetPrefix')]" } } ] } }, { "apiVersion": "2015-05-01-preview", "type": "Microsoft.Network/publicIPAddresses", "name": "[parameters('gatewayPublicIPName')]", "location": "[resourceGroup().location]", "properties": { "publicIPAllocationMethod": "Dynamic" } }, { "apiVersion": "2015-05-01-preview", "type": "Microsoft.Network/virtualNetworkGateways", "name": "[parameters('gatewayName')]", "location": "[resourceGroup().location]", "dependsOn": [ "[concat('Microsoft.Network/publicIPAddresses/', parameters('gatewayPublicIPName'))]", "[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]" ], "properties": { "ipConfigurations": [ { "properties": { "privateIPAllocationMethod": "Dynamic", "subnet": { "id": "[variables('gatewaySubnetRef')]" }, "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses',parameters('gatewayPublicIPName'))]" } }, "name": "vnetGatewayConfig" } ], "gatewayType": "Vpn", "vpnType": "RouteBased", "enableBgp": false } } ] } ================================================ FILE: templates/~arm-templates/S2S-VPN/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "virtualNetworkName": { "value": "new-vnet" }, "localGatewayName": { "value": "localVPN" }, "localGatewayIpAddress": { "value": "203.0.113.1" }, "localGatewayAddressPrefix": { "value": "10.199.0.0/16" }, "gatewayPublicIPName": { "value": "twaz304gwpip1" }, "gatewayName": { "value": "twvpngateway01" }, "addressPrefix": { "value": "10.3.0.0/16" }, "subnet1Prefix": { "value": "10.3.0.0/24" }, "gatewaySubnetPrefix": { "value": "10.3.200.0/29" } } } ================================================ FILE: templates/~arm-templates/app service-cosmos/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "applicationName": { "type": "string", "defaultValue": "[concat('to-do-app', uniqueString(resourceGroup().id))]", "metadata": { "description": "Application Name, max length 30 characters" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } }, "appServicePlanTier": { "type": "string", "defaultValue": "S1", "allowedValues": [ "F1", "D1", "B1", "B2", "B3", "S1", "S2", "S3", "P1", "P2", "P3", "P4" ], "metadata": { "description": "App Service Plan's pricing tier. Details at https://azure.microsoft.com/en-us/pricing/details/app-service/" } }, "appServicePlanInstances": { "type": "int", "defaultValue": 1, "minValue": 1, "maxValue": 3, "metadata": { "description": "App Service Plan's instance count" } }, "repositoryURL": { "type": "string", "defaultValue": "https://github.com/Azure-Samples/cosmos-dotnet-core-todo-app.git", "metadata": { "description": "The URL for the GitHub repository that contains the project to deploy." } }, "branch": { "type": "string", "defaultValue": "main", "metadata": { "description": "The branch of the GitHub repository to use." } }, "databaseName": { "type": "string", "defaultValue": "Tasks", "metadata": { "description": "The Cosmos DB database name." } }, "containerName": { "type": "string", "defaultValue": "Items", "metadata": { "description": "The Cosmos DB container name." } } }, "variables": { "cosmosAccountName": "[toLower(parameters('applicationName'))]", "webSiteName": "[parameters('applicationName')]", "hostingPlanName": "[parameters('applicationName')]" }, "resources": [ { "type": "Microsoft.DocumentDB/databaseAccounts", "name": "[variables('cosmosAccountName')]", "apiVersion": "2021-01-15", "kind": "GlobalDocumentDB", "location": "[parameters('location')]", "properties": { "consistencyPolicy": { "defaultConsistencyLevel": "Session" }, "locations": [ { "locationName": "[parameters('location')]", "failoverPriority": 0, "isZoneRedundant": false } ], "databaseAccountOfferType": "Standard" } }, { "apiVersion": "2019-08-01", "name": "[variables('hostingPlanName')]", "type": "Microsoft.Web/serverfarms", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosAccountName'))]" ], "sku": { "name": "[parameters('appServicePlanTier')]", "capacity": "[parameters('appServicePlanInstances')]" }, "properties": { "name": "[variables('hostingPlanName')]" } }, { "apiVersion": "2019-08-01", "name": "[variables('webSiteName')]", "type": "Microsoft.Web/sites", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]" ], "properties": { "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", "siteConfig": { "appSettings": [ { "name": "CosmosDb:Account", "value": "[reference(resourceId('Microsoft.DocumentDb/databaseAccounts/', variables('cosmosAccountName'))).documentEndpoint]" }, { "name": "CosmosDb:Key", "value": "[listKeys(resourceId('Microsoft.DocumentDb/databaseAccounts', variables('cosmosAccountName')), '2021-01-15').primaryMasterKey]" }, { "name": "CosmosDb:DatabaseName", "value": "[parameters('DatabaseName')]" }, { "name": "CosmosDb:ContainerName", "value": "[parameters('ContainerName')]" } ] } }, "resources": [ { "type": "sourcecontrols", "apiVersion": "2019-08-01", "name": "web", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Web/sites', variables('webSiteName'))]" ], "properties": { "repoUrl": "[parameters('repositoryURL')]", "branch": "[parameters('branch')]", "isManualIntegration": true } } ] } ] } ================================================ FILE: templates/~arm-templates/app service-cosmos/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "applicationName": { "value": "twaz104todowebapp" }, "location": { "value": "East US" } } } ================================================ FILE: templates/~arm-templates/application-gateway/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "location": { "type": "String" }, "applicationGatewayName": { "type": "String" }, "tier": { "type": "String" }, "skuSize": { "type": "String" }, "capacity": { "defaultValue": 2, "type": "Int" }, "subnetName": { "type": "String" }, "zones": { "type": "Array" }, "publicIpAddressName": { "type": "String" }, "sku": { "type": "String" }, "allocationMethod": { "type": "String" }, "publicIpZones": { "type": "Array" }, "autoScaleMaxCapacity": { "type": "Int" } }, "variables": { "vnetId": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/oreilly/providers/Microsoft.Network/virtualNetworks/oreilly-vnet", "publicIPRef": "[resourceId('Microsoft.Network/publicIPAddresses/', parameters('publicIpAddressName'))]", "subnetRef": "[concat(variables('vnetId'), '/subnets/', parameters('subnetName'))]", "applicationGatewayId": "[resourceId('Microsoft.Network/applicationGateways', parameters('applicationGatewayName'))]" }, "resources": [ { "type": "Microsoft.Network/applicationGateways", "apiVersion": "2019-09-01", "name": "[parameters('applicationGatewayName')]", "location": "[parameters('location')]", "dependsOn": [ "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIpAddressName'))]" ], "tags": {}, "zones": "[parameters('zones')]", "properties": { "sku": { "name": "[parameters('skuSize')]", "tier": "[parameters('tier')]" }, "gatewayIPConfigurations": [ { "name": "appGatewayIpConfig", "properties": { "subnet": { "id": "[variables('subnetRef')]" } } } ], "frontendIPConfigurations": [ { "name": "appGwPublicFrontendIp", "properties": { "PublicIPAddress": { "id": "[variables('publicIPRef')]" } } } ], "frontendPorts": [ { "name": "port_80", "properties": { "Port": 80 } } ], "backendAddressPools": [ { "name": "backend-pool", "properties": { "backendAddresses": [] } } ], "backendHttpSettingsCollection": [ { "name": "http-settings", "properties": { "Port": 80, "Protocol": "Http", "cookieBasedAffinity": "Disabled", "requestTimeout": 20 } } ], "httpListeners": [ { "name": "listener-http", "properties": { "frontendIPConfiguration": { "id": "[concat(variables('applicationGatewayId'), '/frontendIPConfigurations/appGwPublicFrontendIp')]" }, "frontendPort": { "id": "[concat(variables('applicationGatewayId'), '/frontendPorts/port_80')]" }, "protocol": "Http", "sslCertificate": null } } ], "requestRoutingRules": [ { "Name": "HTTP", "properties": { "RuleType": "Basic", "httpListener": { "id": "[concat(variables('applicationGatewayId'), '/httpListeners/listener-http')]" }, "backendAddressPool": { "id": "[concat(variables('applicationGatewayId'), '/backendAddressPools/backend-pool')]" }, "backendHttpSettings": { "id": "[concat(variables('applicationGatewayId'), '/backendHttpSettingsCollection/http-settings')]" } } } ], "enableHttp2": false, "sslCertificates": [], "probes": [], "autoscaleConfiguration": { "minCapacity": "[parameters('capacity')]", "maxCapacity": "[parameters('autoScaleMaxCapacity')]" } } }, { "type": "Microsoft.Network/publicIPAddresses", "apiVersion": "2019-02-01", "name": "[parameters('publicIpAddressName')]", "location": "[parameters('location')]", "sku": { "name": "[parameters('sku')]" }, "zones": "[parameters('publicIpZones')]", "properties": { "publicIPAllocationMethod": "[parameters('allocationMethod')]" } }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2017-05-10", "name": "nic1-20210330082219", "dependsOn": [ "[concat('Microsoft.Network/applicationGateways/', parameters('applicationGatewayName'))]" ], "properties": { "mode": "Incremental", "template": { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": {}, "variables": {}, "resources": [ { "name": "nic1", "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/oreilly/providers/Microsoft.Network/networkInterfaces/nic1", "location": "eastus", "properties": { "provisioningState": "Succeeded", "resourceGuid": "1019c06c-bad0-4053-bca9-39207811f919", "ipConfigurations": [ { "name": "ipconfig1", "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/oreilly/providers/Microsoft.Network/networkInterfaces/nic1/ipConfigurations/ipconfig1", "etag": "W/\"4a0581b5-2556-43a1-a6a0-20f021c7d34e\"", "type": "Microsoft.Network/networkInterfaces/ipConfigurations", "properties": { "provisioningState": "Succeeded", "privateIPAddress": "10.10.1.4", "privateIPAllocationMethod": "Dynamic", "subnet": { "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/oreilly/providers/Microsoft.Network/virtualNetworks/oreilly-vnet/subnets/default" }, "primary": true, "privateIPAddressVersion": "IPv4", "applicationGatewayBackendAddressPools": [ { "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/oreilly/providers/Microsoft.Network/applicationGateways/twaz304appgateway/backendAddressPools/backend-pool" } ] } } ], "dnsSettings": { "dnsServers": [], "appliedDnsServers": [], "internalDomainNameSuffix": "n2fsgog5iiouve0yh0mjdu3p0b.bx.internal.cloudapp.net" }, "macAddress": "00-0D-3A-8B-7F-A1", "enableAcceleratedNetworking": false, "enableIPForwarding": false, "primary": true, "virtualMachine": { "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/oreilly/providers/Microsoft.Compute/virtualMachines/oreilly-vm-1" }, "hostedWorkloads": [], "tapConfigurations": [] }, "type": "Microsoft.Network/networkInterfaces", "apiVersion": "2018-10-01", "dependsOn": [] } ] }, "parameters": {} }, "resourceGroup": "oreilly" }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2017-05-10", "name": "nic2-20210330082219", "dependsOn": [ "[concat('Microsoft.Network/applicationGateways/', parameters('applicationGatewayName'))]" ], "properties": { "mode": "Incremental", "template": { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": {}, "variables": {}, "resources": [ { "name": "nic2", "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/oreilly/providers/Microsoft.Network/networkInterfaces/nic2", "location": "eastus", "properties": { "provisioningState": "Succeeded", "resourceGuid": "60f8ad7f-c1b1-4b06-9cec-c441eac145a8", "ipConfigurations": [ { "name": "ipconfig1", "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/oreilly/providers/Microsoft.Network/networkInterfaces/nic2/ipConfigurations/ipconfig1", "etag": "W/\"f416540f-2987-4ec8-a5e5-435ee3b7818e\"", "type": "Microsoft.Network/networkInterfaces/ipConfigurations", "properties": { "provisioningState": "Succeeded", "privateIPAddress": "10.10.1.5", "privateIPAllocationMethod": "Dynamic", "subnet": { "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/oreilly/providers/Microsoft.Network/virtualNetworks/oreilly-vnet/subnets/default" }, "primary": true, "privateIPAddressVersion": "IPv4", "applicationGatewayBackendAddressPools": [ { "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/oreilly/providers/Microsoft.Network/applicationGateways/twaz304appgateway/backendAddressPools/backend-pool" } ] } } ], "dnsSettings": { "dnsServers": [], "appliedDnsServers": [], "internalDomainNameSuffix": "n2fsgog5iiouve0yh0mjdu3p0b.bx.internal.cloudapp.net" }, "macAddress": "00-0D-3A-8C-A8-38", "enableAcceleratedNetworking": false, "enableIPForwarding": false, "primary": true, "virtualMachine": { "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/oreilly/providers/Microsoft.Compute/virtualMachines/oreilly-vm-2" }, "hostedWorkloads": [], "tapConfigurations": [] }, "type": "Microsoft.Network/networkInterfaces", "apiVersion": "2018-10-01", "dependsOn": [] } ] }, "parameters": {} }, "resourceGroup": "oreilly" } ] } ================================================ FILE: templates/~arm-templates/application-gateway/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "location": { "value": "eastus" }, "applicationGatewayName": { "value": "az303appgateway" }, "tier": { "value": "Standard_v2" }, "skuSize": { "value": "Standard_v2" }, "capacity": { "value": 0 }, "subnetName": { "value": "ApplicationGatewaySubnet" }, "zones": { "value": [] }, "publicIpAddressName": { "value": "appgwpip1" }, "sku": { "value": "Standard" }, "allocationMethod": { "value": "Static" }, "publicIpZones": { "value": [] }, "autoScaleMaxCapacity": { "value": 3 } } } ================================================ FILE: templates/~arm-templates/azure-sql-aworks/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "serverName": { "type": "string", "metadata": { "description": "Name of primary SQL server" } }, "secondaryServerName": { "type": "string", "metadata": { "description": "Name of secondary SQL server" } }, "secondaryLocation": { "type": "string", "defaultValue": "westus", "metadata": { "description": "Location of secondary sql server" } }, "sqlDBName": { "type": "string", "defaultValue": "aworks", "metadata": { "description": "The name of the SQL Database." } }, "administratorLogin": { "type": "string", "defaultValue": "tim", "metadata": { "description": "The administrator username of the SQL logical server." } }, "administratorLoginPassword": { "type": "securestring", "metadata": { "description": "The administrator password of the SQL logical server." } } }, "variables": {}, "resources": [ { "type": "Microsoft.Sql/servers", "apiVersion": "2019-06-01-preview", "name": "[parameters('serverName')]", "location": "[resourceGroup().location]", "properties": { "administratorLogin": "[parameters('administratorLogin')]", "administratorLoginPassword": "[parameters('administratorLoginPassword')]" }, "resources": [ { "type": "databases", "apiVersion": "2017-10-01-preview", "name": "[parameters('sqlDBName')]", "location": "[resourceGroup().location]", "sku": { "name": "Standard", "tier": "Standard" }, "properties": { "sampleName": "AdventureWorksLT" }, "dependsOn": [ "[resourceId('Microsoft.Sql/servers', concat(parameters('serverName')))]" ] }, { "name": "nestedDeployment1", "type": "Microsoft.Resources/deployments", "dependsOn": [ "[resourceId('Microsoft.Sql/servers', parameters('serverName'))]" ], "apiVersion": "2019-10-01", "properties": { "expressionEvaluationOptions": { "scope": "outer" }, "mode": "Incremental", "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": {}, "variables": {}, "resources": [ { "name": "[parameters('secondaryServerName')]", "type": "Microsoft.Sql/servers", "apiVersion": "2014-04-01", "location": "[parameters('secondaryLocation')]", "tags": { "displayName": "secondarysqlserver" }, "properties": { "administratorLogin": "[parameters('administratorLogin')]", "administratorLoginPassword": "[parameters('administratorLoginPassword')]" }, "resources": [ { "type": "firewallRules", "apiVersion": "2014-04-01", "dependsOn": [ "[resourceId('Microsoft.Sql/servers', concat(parameters('secondaryServerName')))]" ], "location": "[resourceGroup().location]", "name": "AllowAllWindowsAzureIps", "properties": { "startIpAddress": "0.0.0.0", "endIpAddress": "0.0.0.0" } } ] } ], "outputs": {} } } } ] } ] } ================================================ FILE: templates/~arm-templates/azure-sql-aworks/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "serverName": { "value": "twaz303sqlserver1" }, "secondaryServerName": { "value": "twaz303sqlserver2" }, "sqlDBName": { "value": "aworks" }, "administratorLogin": { "value": "tim" }, "administratorLoginPassword": { "reference": { "keyVault": { "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/TIM/providers/Microsoft.KeyVault/vaults/tim-keyvault-001" }, "secretName": "timvmpw" } } } } ================================================ FILE: templates/~arm-templates/bastion/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "vnet-name": { "type": "string", "defaultValue": "oreilly-vnet", "metadata": { "description": "Name of new or existing vnet to which Azure Bastion should be deployed" } }, "vnet-ip-prefix": { "type": "string", "defaultValue": "10.10.0.0/16", "metadata": { "description": "IP prefix for available addresses in vnet address space" } }, "vnet-new-or-existing": { "type": "string", "allowedValues": [ "new", "existing" ], "defaultValue": "existing", "metadata": { "description": "Specify whether to provision new vnet or deploy to existing vnet" } }, "bastion-subnet-ip-prefix": { "type": "string", "defaultValue": "10.10.3.0/24", "metadata": { "description": "Bastion subnet IP prefix MUST be within vnet IP prefix address space" } }, "bastion-host-name": { "type": "string", "metadata": { "description": "Name of Azure Bastion resource" } } }, "variables": { "public-ip-address-name": "[concat(parameters('bastion-host-name'),'-pip')]", "bastion-subnet-name": "AzureBastionSubnet" }, "resources": [ { "apiVersion": "2020-05-01", "type": "Microsoft.Network/publicIpAddresses", "name": "[variables('public-ip-address-name')]", "location": "[resourceGroup().location]", "sku": { "name": "Standard" }, "properties": { "publicIPAllocationMethod": "Static" } }, { "condition": "[equals(parameters('vnet-new-or-existing'), 'new')]", "apiVersion": "2020-05-01", "name": "[parameters('vnet-name')]", "type": "Microsoft.Network/virtualNetworks", "location": "[resourceGroup().location]", "properties": { "addressSpace": { "addressPrefixes": [ "[parameters('vnet-ip-prefix')]" ] }, "subnets": [ { "name": "[variables('bastion-subnet-name')]", "properties": { "addressPrefix": "[parameters('bastion-subnet-ip-prefix')]" } } ] } }, { "condition": "[equals(parameters('vnet-new-or-existing'), 'existing')]", "apiVersion": "2020-05-01", "type": "Microsoft.Network/virtualNetworks/subnets", "name": "[concat(parameters('vnet-name'), '/', variables('bastion-subnet-name'))]", "location": "[resourceGroup().location]", "properties": { "addressPrefix": "[parameters('bastion-subnet-ip-prefix')]" } }, { "apiVersion": "2020-05-01", "type": "Microsoft.Network/bastionHosts", "name": "[parameters('bastion-host-name')]", "location": "[resourceGroup().location]", "dependsOn": [ "[resourceId('Microsoft.Network/publicIpAddresses', variables('public-ip-address-name'))]", "[resourceId('Microsoft.Network/virtualNetworks', parameters('vnet-name'))]", "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnet-name'), variables('bastion-subnet-name'))]" ], "properties": { "ipConfigurations": [ { "name": "IpConf", "properties": { "subnet": { "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnet-name'), variables('bastion-subnet-name'))]" }, "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIpAddresses', variables('public-ip-address-name'))]" } } } ] } } ] } ================================================ FILE: templates/~arm-templates/bastion/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "bastion-host-name": { "value": "oreilly-vnet-bastion" }, "vnet-name": { "value": "oreilly-vnet" }, "vnet-ip-prefix": { "value": "10.10.0.0/16" }, "bastion-subnet-ip-prefix": { "value": "10.10.3.0/24" } } } ================================================ FILE: templates/~arm-templates/container-registry/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "registries_twaz304acr_name": { "defaultValue": "az303acr001", "type": "String" } }, "variables": {}, "resources": [ { "type": "Microsoft.ContainerRegistry/registries", "apiVersion": "2020-11-01-preview", "name": "[parameters('registries_twaz304acr_name')]", "location": "eastus", "tags": { "class": "az304" }, "sku": { "name": "Standard", "tier": "Standard" }, "properties": { "adminUserEnabled": true, "policies": { "quarantinePolicy": { "status": "disabled" }, "trustPolicy": { "type": "Notary", "status": "disabled" }, "retentionPolicy": { "days": 7, "status": "disabled" } }, "encryption": { "status": "disabled" }, "dataEndpointEnabled": false, "publicNetworkAccess": "Enabled", "networkRuleBypassOptions": "AzureServices", "zoneRedundancy": "Disabled", "anonymousPullEnabled": false } } ] } ================================================ FILE: templates/~arm-templates/container-registry/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "registries_twaz304acr_name": { "value": null } } } ================================================ FILE: templates/~arm-templates/event-hub/eventhub.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "projectName": { "type": "string", "metadata": { "description": "Specifies a project name that is used to generate the Event Hub name and the Namespace name." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Specifies the Azure location for all resources." } }, "eventHubSku": { "type": "string", "defaultValue": "Standard", "allowedValues": [ "Basic", "Standard" ], "metadata": { "description": "Specifies the messaging tier for Event Hub Namespace." } } }, "variables": { "eventHubNamespaceName": "[concat(parameters('projectName'), 'ns')]", "eventHubName": "[parameters('projectName')]" }, "resources": [ { "type": "Microsoft.EventHub/namespaces", "apiVersion": "2018-01-01-preview", "name": "[variables('eventHubNamespaceName')]", "location": "[parameters('location')]", "sku": { "name": "[parameters('eventHubSku')]", "tier": "[parameters('eventHubSku')]", "capacity": 1 }, "properties": { "isAutoInflateEnabled": false, "maximumThroughputUnits": 0 } }, { "type": "Microsoft.EventHub/namespaces/eventhubs", "apiVersion": "2017-04-01", "name": "[concat(variables('eventHubNamespaceName'), '/', variables('eventHubName'))]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.EventHub/namespaces', variables('eventHubNamespaceName'))]" ], "properties": { "messageRetentionInDays": 7, "partitionCount": 1 } } ] } ================================================ FILE: templates/~arm-templates/event-hub/eventhub.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "projectName": { "value": "twaz303" } } } ================================================ FILE: templates/~arm-templates/firewall/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "vNetName": { "type": "string", "defaultValue": "oreilly-vnet", "metadata": { "description": "Target virtual network name" } }, "firewallName": { "type": "string", "defaultValue": "tlwfw001", "metadata": { "description": "Azure Firewall hostname" } }, "publicIPName": { "type": "string", "defaultValue": "tfwpip001", "metadata": { "description": "Hostname of public IP address resource" } }, "vNetResourceGroup": { "type": "string", "defaultValue": "[resourceGroup().name]", "metadata": { "description": "Resource group of the parent virtual network" } } }, "functions": [], "variables": {}, "resources": [ { "name": "[parameters('firewallName')]", "type": "Microsoft.Network/azureFirewalls", "apiVersion": "2019-11-01", "location": "[resourceGroup().location]", "tags": { }, "properties": { "applicationRuleCollections": [ { "name": "appCollectionName1", "properties": { "priority": 100, "action": { "type": "Allow" }, "rules": [ { "name": "appRuleName1", "description": "appRuleDescription", "sourceAddresses": [ "10.10.4.4" ], "protocols": [ { "protocolType": "Http", "port": 80 } ], "targetFqdns": [ "www.microsoft.com" ], "fqdnTags": [ ] } ] } } ], "natRuleCollections": [ { "name": "natCollectionName1", "properties": { "priority": 100, "action": { "type": "Dnat" }, "rules": [ { "name": "natRuleName1", "description": "natRuleDescription", "sourceAddresses": [ "10.10.4.4" ], "destinationAddresses": [ "[reference(resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPName'))).ipAddress]" ], "destinationPorts": [ "3389" ], "protocols": [ "TCP" ], "translatedAddress": "10.0.0.254", "translatedPort": "2500" } ] } } ], "networkRuleCollections": [ { "name": "networkCollectionName", "properties": { "priority": 100, "action": { "type": "Deny" }, "rules": [ { "name": "networkRuleName", "description": "networkRuleDescription", "sourceAddresses": [ "10.10.4.4" ], "destinationAddresses": [ "10.10.4.4" ], "destinationPorts": [ "1" ], "protocols": [ "TCP" ] } ] } } ], "ipConfigurations": [ { "name": "ipConfigName", "properties": { "subnet": { "id": "[resourceId(parameters('vNetResourceGroup'), 'Microsoft.Network/virtualNetworks/subnets', parameters('vNetName'), 'AzureFirewallSubnet')]" }, "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPName'))]" } } } ] }, "dependsOn": [ "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPName'))]" ] }, { "name": "[parameters('publicIPName')]", "type": "Microsoft.Network/publicIPAddresses", "apiVersion": "2019-11-01", "location": "[resourceGroup().location]", "sku": { "name": "standard" }, "tags": { "owner": "tim@timw.info" }, "properties": { "publicIPAllocationMethod": "Static", "dnsSettings": { "domainNameLabel": "[concat('twfw001', uniqueString(resourceGroup().id))]" } } } ], "outputs": {} } ================================================ FILE: templates/~arm-templates/firewall/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "vNetName": { "value": "oreilly-vnet" }, "firewallName": { "value": "oreilly-firewall" }, "publicIPName": { "value": "twaz500fw-pip" }, "vNetResourceGroup": { "value": "oreilly" } } } ================================================ FILE: templates/~arm-templates/iot-hub/iothub.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "hubname": { "type": "string", "defaultValue":"twaziothub001" }, "sku_name": { "type": "string", "defaultValue": "S1", "allowedValues": [ "F1", "S1" ] }, "sku_units": { "type": "string", "defaultValue": "1" }, "d2c_partitions": { "type": "string", "defaultValue": "4" }, "features": { "type": "string", "defaultValue": "None", "allowedValues": [ "None", "DeviceManagement" ] } }, "resources": [ { "apiVersion": "2020-07-10-preview", "type": "Microsoft.Devices/IotHubs", "name": "[parameters('hubname')]", "location": "[resourceGroup().location]", "properties": { "eventHubEndpoints": { "events": { "retentionTimeInDays": 1, "partitionCount": "[parameters('d2c_partitions')]" } }, "features": "[parameters('features')]" }, "sku": { "name": "[parameters('sku_name')]", "capacity": "[parameters('sku_units')]" } }, { "type": "Microsoft.Security/IoTSecuritySolutions", "apiVersion": "2019-08-01", "name": "[parameters('hubname')]", "location": "[resourceGroup().location]", "properties": { "status": "Enabled", "unmaskedIpLoggingStatus": "Enabled", "disabledDataSources": [], "displayName": "[parameters('hubname')]", "iotHubs": [ "[resourceId('Microsoft.Devices/IotHubs', parameters('hubname'))]" ], "recommendationsConfiguration": [] }, "dependsOn": [ "[resourceId('Microsoft.Devices/IotHubs', parameters('hubname'))]" ] } ] } ================================================ FILE: templates/~arm-templates/iot-hub/iothub.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "hubname": { "value": "twaziothub001" } } } ================================================ FILE: templates/~arm-templates/linux-vm-password/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "type": "string", "metadata": { "description": "User name for the Virtual Machine." } }, "dnsLabelPrefix": { "type": "string", "metadata": { "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } }, "authenticationType": { "type": "string", "defaultValue": "password", "allowedValues": [ "sshPublicKey", "password" ], "metadata": { "description": "Type of authentication to use on the Virtual Machine. SSH key is recommended." } }, "adminPasswordOrKey": { "type": "securestring", "metadata": { "description": "SSH Key or password for the Virtual Machine. SSH key is recommended." } }, "vmSize": { "type": "string", "defaultValue": "Standard_D3_v2", "metadata": { "description": "Size of the virtual machine." } } }, "variables": { "imagePublisher": "Canonical", "imageOffer": "UbuntuServer", "ubuntuOSVersion": "18.04-LTS", "nicName": "myVMNic2", "addressPrefix": "10.10.0.0/16", "subnetName": "workload2", "subnetPrefix": "10.10.3.0/24", "storageAccountName": "[concat('stglinuxvm2', uniquestring(resourceGroup().id))]", "storageAccountSkuName": "Standard_LRS", "storageAccountSkuType": "Standard", "storageAccountKind": "StorageV2", "publicIPAddressName": "myPublicIP22", "publicIPAddressType": "Dynamic", "vmName": "oreilly-linux", "virtualNetworkName": "oreilly-hub-vnet", "linuxConfiguration": { "disablePasswordAuthentication": false, "ssh": { "publicKeys": [ { "path": "[concat('/home/', parameters('adminUsername'), '/.ssh/authorized_keys')]", "keyData": "[parameters('adminPasswordOrKey')]" } ] } }, "networkSecurityGroupName": "default-NSG" }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "name": "[variables('storageAccountName')]", "apiVersion": "2019-06-01", "location": "[parameters('location')]", "sku": { "name": "[variables('storageAccountSkuName')]", "tier": "[variables('storageAccountSkuType')]" }, "kind": "[variables('storageAccountKind')]", "properties": {} }, { "type": "Microsoft.Network/publicIPAddresses", "name": "[variables('publicIPAddressName')]", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "properties": { "publicIPAllocationMethod": "[variables('publicIPAddressType')]", "dnsSettings": { "domainNameLabel": "[parameters('dnsLabelPrefix')]" } } }, { "comments": "Default Network Security Group for template", "type": "Microsoft.Network/networkSecurityGroups", "apiVersion": "2020-05-01", "name": "[variables('networkSecurityGroupName')]", "location": "[parameters('location')]", "properties": { "securityRules": [ { "name": "default-allow-22", "properties": { "priority": 1000, "access": "Allow", "direction": "Inbound", "destinationPortRange": "22", "protocol": "Tcp", "sourceAddressPrefix": "*", "sourcePortRange": "*", "destinationAddressPrefix": "*" } } ] } }, { "type": "Microsoft.Network/virtualNetworks", "name": "[variables('virtualNetworkName')]", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" ], "properties": { "addressSpace": { "addressPrefixes": [ "[variables('addressPrefix')]" ] }, "subnets": [ { "name": "[variables('subnetName')]", "properties": { "addressPrefix": "[variables('subnetPrefix')]", "networkSecurityGroup": { "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" } } } ] } }, { "type": "Microsoft.Network/networkInterfaces", "name": "[variables('nicName')]", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", "[resourceId('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" ], "properties": { "primary": true, "enableAcceleratedNetworking": true, "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Dynamic", "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]" }, "subnet": { "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), variables('subnetName'))]" } } } ] } }, { "type": "Microsoft.Compute/virtualMachines", "name": "[variables('vmName')]", "apiVersion": "2019-07-01", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]", "[resourceId('Microsoft.Network/networkInterfaces/', variables('nicName'))]" ], "properties": { "hardwareProfile": { "vmSize": "[parameters('vmSize')]" }, "osProfile": { "computerName": "[variables('vmName')]", "adminUsername": "[parameters('adminUsername')]", "adminPassword": "[parameters('adminPasswordOrKey')]", "linuxConfiguration": "[if(equals(parameters('authenticationType'), 'password'), json('null'), variables('linuxConfiguration'))]" }, "storageProfile": { "imageReference": { "publisher": "[variables('imagePublisher')]", "offer": "[variables('imageOffer')]", "sku": "[variables('ubuntuOSVersion')]", "version": "latest" }, "osDisk": { "createOption": "FromImage" }, "dataDisks": [ { "diskSizeGB": 1023, "lun": 0, "createOption": "Empty" } ] }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]" } ] }, "diagnosticsProfile": { "bootDiagnostics": { "enabled": true, "storageUri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')), '2019-06-01').primaryEndpoints.blob)]" } } } } ], "outputs": { "hostname": { "type": "string", "value": "[reference(variables('publicIPAddressName')).dnsSettings.fqdn]" }, "sshCommand": { "type": "string", "value": "[concat('ssh ', parameters('adminUsername'), '@', reference(variables('publicIPAddressName')).dnsSettings.fqdn)]" } } } ================================================ FILE: templates/~arm-templates/linux-vm-password/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "value": "tim" }, "dnsLabelPrefix": { "value": "oreilly-lin-pip1" }, "adminPasswordOrKey": { "reference": { "keyVault": { "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/TIM/providers/Microsoft.KeyVault/vaults/tim-keyvault-001" }, "secretName": "timvmpw" } } } } ================================================ FILE: templates/~arm-templates/linux-vm-ssh/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "projectName": { "type": "string", "metadata": { "description": "Specifies a name for generating resource names." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Specifies the location for all resources." } }, "adminUsername": { "type": "string", "metadata": { "description": "Specifies a username for the Virtual Machine." } }, "adminPublicKey": { "type": "string", "metadata": { "description": "Specifies the SSH rsa public key file as a string. Use \"ssh-keygen -t rsa -b 2048\" to generate your SSH key pairs." } }, "vmSize": { "type": "string", "defaultValue": "Standard_B2ms", "metadata": { "description": "description" } } }, "variables": { "vNetName": "[concat(parameters('projectName'), '-vnet')]", "vNetAddressPrefixes": "10.10.0.0/16", "vNetSubnetName": "workload", "vNetSubnetAddressPrefix": "10.10.2.0/24", "vmName": "[concat(parameters('projectName'), '-vm')]", "publicIPAddressName": "[concat(parameters('projectName'), '-ip')]", "networkInterfaceName": "[concat(parameters('projectName'), '-nic')]", "networkSecurityGroupName": "[concat(parameters('projectName'), '-nsg')]", "networkSecurityGroupName2": "[concat(variables('vNetSubnetName'), '-nsg')]" }, "resources": [ { "type": "Microsoft.Network/networkSecurityGroups", "apiVersion": "2020-05-01", "name": "[variables('networkSecurityGroupName')]", "location": "[parameters('location')]", "properties": { "securityRules": [ { "name": "ssh_rule", "properties": { "description": "Locks inbound down to ssh default port 22.", "protocol": "Tcp", "sourcePortRange": "*", "destinationPortRange": "22", "sourceAddressPrefix": "*", "destinationAddressPrefix": "*", "access": "Allow", "priority": 123, "direction": "Inbound" } } ] } }, { "type": "Microsoft.Network/publicIPAddresses", "apiVersion": "2020-05-01", "name": "[variables('publicIPAddressName')]", "location": "[parameters('location')]", "properties": { "publicIPAllocationMethod": "Dynamic" }, "sku": { "name": "Basic" } }, { "comments": "Simple Network Security Group for subnet [variables('vNetSubnetName')]", "type": "Microsoft.Network/networkSecurityGroups", "apiVersion": "2020-05-01", "name": "[variables('networkSecurityGroupName2')]", "location": "[parameters('location')]", "properties": { "securityRules": [ { "name": "default-allow-22", "properties": { "priority": 1000, "access": "Allow", "direction": "Inbound", "destinationPortRange": "22", "protocol": "Tcp", "sourceAddressPrefix": "*", "sourcePortRange": "*", "destinationAddressPrefix": "*" } } ] } }, { "type": "Microsoft.Network/virtualNetworks", "apiVersion": "2020-05-01", "name": "[variables('vNetName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName2'))]" ], "properties": { "addressSpace": { "addressPrefixes": [ "[variables('vNetAddressPrefixes')]" ] }, "subnets": [ { "name": "[variables('vNetSubnetName')]", "properties": { "addressPrefix": "[variables('vNetSubnetAddressPrefix')]", "networkSecurityGroup": { "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName2'))]" } } } ] } }, { "type": "Microsoft.Network/networkInterfaces", "apiVersion": "2020-05-01", "name": "[variables('networkInterfaceName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]", "[resourceId('Microsoft.Network/virtualNetworks', variables('vNetName'))]", "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" ], "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Dynamic", "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]" }, "subnet": { "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('vNetName'), variables('vNetSubnetName'))]" } } } ] } }, { "type": "Microsoft.Compute/virtualMachines", "apiVersion": "2019-12-01", "name": "[variables('vmName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]" ], "properties": { "hardwareProfile": { "vmSize": "[parameters('vmSize')]" }, "osProfile": { "computerName": "[variables('vmName')]", "adminUsername": "[parameters('adminUsername')]", "linuxConfiguration": { "disablePasswordAuthentication": true, "ssh": { "publicKeys": [ { "path": "[concat('/home/', parameters('adminUsername'), '/.ssh/authorized_keys')]", "keyData": "[parameters('adminPublicKey')]" } ] } } }, "storageProfile": { "imageReference": { "publisher": "Canonical", "offer": "UbuntuServer", "sku": "18.04-LTS", "version": "latest" }, "osDisk": { "createOption": "fromImage" } }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]" } ] } } } ] } ================================================ FILE: templates/~arm-templates/linux-vm-ssh/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "projectName": { "value": "lin" }, "adminUsername": { "value": "tim" }, "adminPublicKey": { "reference": { "keyVault": { "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/TIM/providers/Microsoft.KeyVault/vaults/tim-keyvault-001" }, "secretName": "ssh-pubkey" } } } } ================================================ FILE: templates/~arm-templates/load-balancer/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "loadBalancerName": { "type": "string", "defaultValue": "cf-lb" }, "loadBalancerPublicIPAddressName": { "type": "string", "defaultValue": "foo" } }, "variables": { "publicIPAddressID": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('loadBalancerPublicIPAddressName'))]", "lbID": "[resourceId('Microsoft.Network/loadBalancers', parameters('loadBalancerName'))]", "frontEndIPConfigID": "[concat(variables('lbID'), '/frontendIPConfigurations/LoadBalancerFrontEnd')]", "lbPoolID": "[concat(variables('lbID'), '/backendAddressPools/BackendPool')]", "lbProbeID": "[concat(variables('lbID'), '/probes/healthProbe')]" }, "resources": [ { "apiVersion": "2017-08-01", "type": "Microsoft.Network/publicIPAddresses", "name": "[parameters('loadBalancerPublicIPAddressName')]", "location": "[resourceGroup().location]", "sku": { "name": "Standard" }, "properties": { "publicIPAllocationMethod": "static" } }, { "apiVersion": "2017-08-01", "name": "[parameters('loadBalancerName')]", "type": "Microsoft.Network/loadBalancers", "location": "[resourceGroup().location]", "sku": { "name": "Standard" }, "dependsOn": [ "[concat('Microsoft.Network/publicIPAddresses/', parameters('loadBalancerPublicIPAddressName'))]" ], "properties": { "frontendIPConfigurations": [ { "name": "LoadBalancerFrontEnd", "properties": { "publicIPAddress": { "id": "[variables('publicIPAddressID')]" } } } ], "backendAddressPools": [ { "name": "BackendPool" } ], "loadBalancingRules": [ { "name": "https", "properties": { "frontendIPConfiguration": { "id": "[variables('frontEndIPConfigID')]" }, "backendAddressPool": { "id": "[variables('lbPoolID')]" }, "protocol": "Tcp", "frontendPort": 443, "backendPort": 443, "enableFloatingIP": false, "idleTimeoutInMinutes": 15, "probe": { "id": "[variables('lbProbeID')]" } } }, { "name": "http", "properties": { "frontendIPConfiguration": { "id": "[variables('frontEndIPConfigID')]" }, "backendAddressPool": { "id": "[variables('lbPoolID')]" }, "protocol": "Tcp", "frontendPort": 80, "backendPort": 80, "enableFloatingIP": false, "idleTimeoutInMinutes": 15, "probe": { "id": "[variables('lbProbeID')]" } } }, { "name": "ntp", "properties": { "frontendIPConfiguration": { "id": "[variables('frontEndIPConfigID')]" }, "backendAddressPool": { "id": "[variables('lbPoolID')]" }, "protocol": "udp", "frontendPort": 123, "backendPort": 123, "enableFloatingIP": false, "idleTimeoutInMinutes": 15, "probe": { "id": "[variables('lbProbeID')]" } } } ], "probes": [ { "name": "healthProbe", "properties": { "protocol": "HTTP", "port": 8080, "intervalInSeconds": 5, "numberOfProbes": 2, "requestPath": "/health" } } ] } } ], "outputs": { "loadBalancerPublicIPAddress": { "type": "string", "value": "[reference(parameters('loadBalancerPublicIPAddressName')).ipAddress]" } } } ================================================ FILE: templates/~arm-templates/load-balancer/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "loadBalancerName": { "value": "cf-lb" }, "loadBalancerPublicIPAddressName": { "value": "foo" } } } ================================================ FILE: templates/~arm-templates/multiple-vms/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "type": "string", "metadata": { "description": "Admin username for VM" } }, "numberOfInstances": { "type": "int", "minValue": 2, "maxValue": 5, "defaultValue": 2, "metadata": { "description": "Number of VMs to deploy, limit 5 since this sample is using a single storage account" } }, "OS": { "type": "string", "defaultValue": "Windows", "allowedValues": [ "Ubuntu", "Windows" ], "metadata": { "description": "OS Platform for the VM" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } }, "authenticationType": { "type": "string", "defaultValue": "password", "allowedValues": [ "sshPublicKey", "password" ], "metadata": { "description": "Type of authentication to use on the Virtual Machine. SSH key is recommended." } }, "adminPasswordOrKey": { "type": "securestring", "metadata": { "description": "SSH Key or password for the Virtual Machine. SSH key is recommended." } }, "vmSize": { "type": "string", "defaultValue": "Standard_B2ms", "metadata": { "description": "description" } }, "vNetName": { "type": "string", "defaultValue": "oreilly-vnet" }, "addressRange": { "type": "string", "defaultValue":"10.10.0.0/16" }, "subnetName": { "type": "string", "defaultValue":"web" }, "subnetPrefix": { "type": "string", "defaultValue": "10.10.1.0/24" }, "avSetName": { "type": "string", "defaultValue": "tw-avset" }, "nsgName": { "type": "string", "defaultValue":"oreilly-nsg-web" } }, "variables": { "addressPrefix": "[parameters('addressRange')]", "subnet1Ref": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vNetName'),parameters('subnetName'))]", "availabilitySetName": "[parameters('avSetName')]", "imageReference": { "Ubuntu": { "publisher": "Canonical", "offer": "UbuntuServer", "sku": "18.04-LTS", "version": "latest" }, "Windows": { "publisher": "MicrosoftWindowsServer", "offer": "WindowsServer", "sku": "2019-Datacenter", "version": "latest" } }, "networkSecurityGroupName": "[parameters('nsgName')]", "nsgOsPort": { "Ubuntu": "22", "Windows": "3389" }, "linuxConfiguration": { "disablePasswordAuthentication": true, "ssh": { "publicKeys": [ { "path": "[concat('/home/', parameters('adminUsername'), '/.ssh/authorized_keys')]", "keyData": "[parameters('adminPasswordOrKey')]" } ] } } }, "resources": [ { "type": "Microsoft.Compute/availabilitySets", "name": "[variables('availabilitySetName')]", "apiVersion": "2019-07-01", "location": "[parameters('location')]", "properties": { "platformFaultDomainCount": 2, "platformUpdateDomainCount": 2 }, "sku": { "name": "Aligned" } }, { "comments": "Default Network Security Group for template", "type": "Microsoft.Network/networkSecurityGroups", "apiVersion": "2020-05-01", "name": "[parameters('nsgName')]", "location": "[parameters('location')]", "properties": { "securityRules": [ { "name": "[concat('default-allow-', variables('nsgOsPort')[parameters('OS')])]", "properties": { "priority": 1000, "access": "Allow", "direction": "Inbound", "destinationPortRange": "[variables('nsgOsPort')[parameters('OS')]]", "protocol": "Tcp", "sourceAddressPrefix": "*", "sourcePortRange": "*", "destinationAddressPrefix": "*" } } ] } }, { "type": "Microsoft.Network/networkInterfaces", "name": "[concat('nic', copyindex(1))]", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "copy": { "name": "nicLoop", "count": "[parameters('numberOfInstances')]" }, "dependsOn": [ "[parameters('vNetName')]" ], "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Dynamic", "subnet": { "id": "[variables('subnet1Ref')]" } } } ] } }, { "type": "Microsoft.Compute/virtualMachines", "name": "[concat('oreilly-vm-', copyIndex(1))]", "apiVersion": "2019-07-01", "location": "[parameters('location')]", "copy": { "name": "virtualMachineLoop", "count": "[parameters('numberOfInstances')]" }, "dependsOn": [ "nicLoop" ], "properties": { "availabilitySet": { "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]" }, "hardwareProfile": { "vmSize": "[parameters('vmSize')]" }, "osProfile": { "computerName": "[concat('oreilly-vm-', copyIndex(1))]", "adminUsername": "[parameters('adminUsername')]", "adminPassword": "[parameters('adminPasswordOrKey')]", "linuxConfiguration": "[if(equals(parameters('authenticationType'), 'password'), json('null'), variables('linuxConfiguration'))]" }, "storageProfile": { "imageReference": "[variables('imageReference')[parameters('OS')]]", "osDisk": { "createOption": "FromImage" } }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces',concat('nic', copyindex(1)))]" } ] } } } ] } ================================================ FILE: templates/~arm-templates/multiple-vms/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "value": "tim" }, "OS": { "value": "Windows" }, "numberOfInstances": { "value": 2 }, "adminPasswordOrKey": { "reference": { "keyVault": { "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/TIM/providers/Microsoft.KeyVault/vaults/tim-keyvault-001" }, "secretName": "vmp" } } } } ================================================ FILE: templates/~arm-templates/new-AD-forest/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "type": "string", "metadata": { "description": "Admin username for the AD VMs" } }, "adminPassword": { "type": "secureString", "metadata": { "description": "Admin password for the AD VMs" } }, "domainName": { "type": "string", "metadata": { "description": "Domain name for the AD Controller" } }, "dnsPrefix": { "type": "string", "metadata": { "description": "PublicIp DNS prefix for the AD Controller" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources" } } }, "resources": [ { "name": "createADController", "type": "Microsoft.Resources/deployments", "apiVersion": "2020-06-01", "properties": { "mode": "Incremental", "templateLink": { "uri": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/modules/active-directory-new-domain/0.9/azuredeploy.json", "contentVersion": "1.0.0.0" }, "parameters": { "adminUsername": { "value": "[parameters('adminUsername')]" }, "adminPassword": { "value": "[parameters('adminPassword')]" }, "domainName": { "value": "[parameters('domainName')]" }, "dnsPrefix": { "value": "[parameters('dnsPrefix')]" }, "location": { "value": "[parameters('location')]" } } } } ], "outputs": { "output": { "type": "object", "value": "[reference('createADController').outputs]" } } } ================================================ FILE: templates/~arm-templates/new-AD-forest/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "value": "tim" }, "adminPassword": { "reference": { "keyVault": { "id": "/subscriptions/2fbf906e-1101-4bc0-b64f-adc44e462fff/resourceGroups/TIM/providers/Microsoft.KeyVault/vaults/tim-keyvault-001" }, "secretName": "timvmpw" } }, "domainName": { "value": "company.pri" }, "dnsPrefix": { "value": "companypri-pip" } } } ================================================ FILE: templates/~arm-templates/private-dns-zone/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "privateDnsZoneName": { "type": "string", "defaultValue": "oreilly.pri", "metadata": { "description": "Private DNS zone name" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } } }, "resources": [ { "type": "Microsoft.Network/privateDnsZones", "apiVersion": "2020-01-01", "name": "[parameters('privateDnsZoneName')]", "location": "global" } ] } ================================================ FILE: templates/~arm-templates/private-dns-zone/azuredeploy.parameters.json ================================================ ================================================ FILE: templates/~arm-templates/traffic-manager/trafficmanager.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "trafficManagerProfiles_twaz304tm_name": { "defaultValue": "twaz304tm", "type": "String" } }, "variables": {}, "resources": [ { "type": "Microsoft.Network/trafficManagerProfiles", "apiVersion": "2018-04-01", "name": "[parameters('trafficManagerProfiles_twaz304tm_name')]", "location": "global", "tags": { "class": "az304" }, "properties": { "profileStatus": "Enabled", "trafficRoutingMethod": "Performance", "dnsConfig": { "relativeName": "[parameters('trafficManagerProfiles_twaz304tm_name')]", "ttl": 60 }, "monitorConfig": { "profileMonitorStatus": "Inactive", "protocol": "HTTP", "port": 80, "path": "/", "intervalInSeconds": 30, "toleratedNumberOfFailures": 3, "timeoutInSeconds": 10 }, "endpoints": [], "trafficViewEnrollmentStatus": "Disabled", "maxReturn": 0 } } ] } ================================================ FILE: templates/~arm-templates/traffic-manager/trafficmanager.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "trafficManagerProfiles_twaz304tm_name": { "value": null } } } ================================================ FILE: templates/~arm-templates/virtual-network/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "vnetName": { "type": "string", "metadata": { "description": "VNet name" } }, "vnetAddressPrefix": { "type": "string", "metadata": { "description": "Address prefix" } }, "subnet1Prefix": { "type": "string", "metadata": { "description": "Subnet 1 Prefix" } }, "subnet1Name": { "type": "string", "metadata": { "description": "Subnet 1 Name" } }, "subnet2Prefix": { "type": "string", "metadata": { "description": "Subnet 2 Prefix" } }, "subnet2Name": { "type": "string", "metadata": { "description": "Subnet 2 Name" } }, "subnet3Prefix": { "type": "string", "metadata": { "description": "Subnet 3 Prefix" } }, "subnet3Name": { "type": "string", "metadata": { "description": "Subnet 3 Name" } }, "subnet4Prefix": { "type": "string", "metadata": { "description": "Subnet 4 Prefix" } }, "subnet4Name": { "type": "string", "metadata": { "description": "Subnet 4 Name" } }, "subnet5Prefix": { "type": "string", "metadata": { "description": "Subnet 5 Prefix" } }, "subnet5Name": { "type": "string", "metadata": { "description": "Subnet 5 Name" } }, "subnet6Prefix": { "type": "string", "metadata": { "description": "Subnet 6 Prefix" } }, "subnet6Name": { "type": "string", "metadata": { "description": "Subnet 6 Name" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } } }, "variables": {}, "resources": [ { "type": "Microsoft.Network/virtualNetworks", "apiVersion": "2020-05-01", "name": "[parameters('vnetName')]", "location": "[parameters('location')]", "properties": { "addressSpace": { "addressPrefixes": [ "[parameters('vnetAddressPrefix')]" ] } }, "resources": [ { "type": "subnets", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "name": "[parameters('subnet1Name')]", "dependsOn": [ "[parameters('vnetName')]" ], "properties": { "addressPrefix": "[parameters('subnet1Prefix')]" } }, { "type": "subnets", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "name": "[parameters('subnet2Name')]", "dependsOn": [ "[parameters('vnetName')]", "[parameters('subnet1Name')]" ], "properties": { "addressPrefix": "[parameters('subnet2Prefix')]" } }, { "type": "subnets", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "name": "[parameters('subnet3Name')]", "dependsOn": [ "[parameters('vnetName')]", "[parameters('subnet2Name')]" ], "properties": { "addressPrefix": "[parameters('subnet3Prefix')]" } }, { "type": "subnets", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "name": "[parameters('subnet4Name')]", "dependsOn": [ "[parameters('vnetName')]", "[parameters('subnet3Name')]" ], "properties": { "addressPrefix": "[parameters('subnet4Prefix')]" } }, { "type": "subnets", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "name": "[parameters('subnet5Name')]", "dependsOn": [ "[parameters('vnetName')]", "[parameters('subnet4Name')]" ], "properties": { "addressPrefix": "[parameters('subnet5Prefix')]" } }, { "type": "subnets", "apiVersion": "2020-05-01", "location": "[parameters('location')]", "name": "[parameters('subnet6Name')]", "dependsOn": [ "[parameters('vnetName')]", "[parameters('subnet5Name')]" ], "properties": { "addressPrefix": "[parameters('subnet6Prefix')]" } } ] } ] } ================================================ FILE: templates/~arm-templates/virtual-network/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "vnetName": { "value": "oreilly-vnet" }, "vnetAddressPrefix": { "value": "10.10.0.0/16" }, "subnet1Prefix": { "value": "10.10.1.0/24" }, "subnet1Name": { "value": "web" }, "subnet2Prefix": { "value": "10.10.2.0/24" }, "subnet2Name": { "value": "workload" }, "subnet3Prefix": { "value": "10.10.3.0/24" }, "subnet3Name": { "value": "AzureBastionSubnet" }, "subnet4Prefix": { "value": "10.10.4.0/24" }, "subnet4Name": { "value": "AzureFirewallSubnet" }, "subnet5Prefix": { "value": "10.10.5.0/24" }, "subnet5Name": { "value": "ApplicationGatewaySubnet" }, "subnet6Prefix": { "value": "10.10.6.0/24" }, "subnet6Name": { "value": "GatewaySubnet" } } } ================================================ FILE: templates/~arm-templates/windows-vm-cse/azuredeploy.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "type": "string", "metadata": { "description": "Username for the Virtual Machine." } }, "adminPassword": { "type": "securestring", "metadata": { "description": "Password for the Virtual Machine." } }, "dnsLabelPrefix": { "type": "string", "defaultValue": "[toLower(concat(parameters('vmName'),'-', uniqueString(resourceGroup().id, parameters('vmName'))))]", "metadata": { "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." } }, "publicIpName": { "type": "string", "defaultValue": "myPublicIP", "metadata": { "description": "Name for the Public IP used to access the Virtual Machine." } }, "publicIPAllocationMethod": { "type": "string", "defaultValue": "Dynamic", "allowedValues": [ "Dynamic", "Static" ], "metadata": { "description": "Allocation method for the Public IP used to access the Virtual Machine." } }, "publicIpSku": { "type": "string", "defaultValue": "Basic", "allowedValues": [ "Basic", "Standard" ], "metadata": { "description": "SKU for the Public IP used to access the Virtual Machine." } }, "OSVersion": { "type": "string", "defaultValue": "2019-Datacenter", "allowedValues": [ "2008-R2-SP1", "2012-Datacenter", "2012-R2-Datacenter", "2016-Nano-Server", "2016-Datacenter-with-Containers", "2016-Datacenter", "2019-Datacenter", "2019-Datacenter-Core", "2019-Datacenter-Core-smalldisk", "2019-Datacenter-Core-with-Containers", "2019-Datacenter-Core-with-Containers-smalldisk", "2019-Datacenter-smalldisk", "2019-Datacenter-with-Containers", "2019-Datacenter-with-Containers-smalldisk" ], "metadata": { "description": "The Windows version for the VM. This will pick a fully patched image of this given Windows version." } }, "vmSize": { "type": "string", "defaultValue": "Standard_B2ms", "allowedValues": [ "Standard_B2ms", "Standard_D2s_v4", "Standard_B4ms", "Standard_D4s_v4" ], "metadata": { "description": "Size of the virtual machine." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } }, "vmName": { "type": "string", "defaultValue": "simple-vm", "metadata": { "description": "Name of the virtual machine." } }, "nicPrefix": { "type": "string", "metadata": { "description": "description" } }, "vnetName": { "type": "string", "metadata": { "description": "description" } }, "vnetAddressPrefix": { "type": "string", "metadata": { "description": "description" } }, "subnetName": { "type": "string", "metadata": { "description": "description" } }, "subnetPrefix": { "type": "string", "metadata": { "description": "description" } } }, "variables": { "storageAccountName": "[concat('bootdiags', uniquestring(resourceGroup().id))]", "nicName": "[concat(parameters('nicPrefix'), '-nic')]", "addressPrefix": "[parameters('vnetAddressPrefix')]", "subnetName": "[parameters('subnetName')]", "subnetPrefix": "[parameters('subnetPrefix')]", "virtualNetworkName": "[parameters('vnetName')]", "subnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), variables('subnetName'))]", "networkSecurityGroupName": "default-NSG" }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2019-06-01", "name": "[variables('storageAccountName')]", "location": "[parameters('location')]", "sku": { "name": "Standard_LRS" }, "kind": "Storage", "properties": {} }, { "type": "Microsoft.Network/publicIPAddresses", "apiVersion": "2020-05-01", "name": "[parameters('publicIPName')]", "location": "[parameters('location')]", "sku": { "name": "[parameters('publicIpSku')]" }, "properties": { "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", "dnsSettings": { "domainNameLabel": "[parameters('dnsLabelPrefix')]" } } }, { "type": "Microsoft.Network/networkSecurityGroups", "apiVersion": "2020-05-01", "name": "[variables('networkSecurityGroupName')]", "location": "[parameters('location')]", "properties": { "securityRules": [ { "name": "default-allow-3389", "properties": { "priority": 1000, "access": "Allow", "direction": "Inbound", "destinationPortRange": "3389", "protocol": "Tcp", "sourcePortRange": "*", "sourceAddressPrefix": "*", "destinationAddressPrefix": "*" } } ] } }, { "type": "Microsoft.Network/virtualNetworks", "apiVersion": "2020-05-01", "name": "[variables('virtualNetworkName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" ], "properties": { "addressSpace": { "addressPrefixes": [ "[variables('addressPrefix')]" ] }, "subnets": [ { "name": "[variables('subnetName')]", "properties": { "addressPrefix": "[variables('subnetPrefix')]", "networkSecurityGroup": { "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" } } } ] } }, { "type": "Microsoft.Network/networkInterfaces", "apiVersion": "2020-05-01", "name": "[variables('nicName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPName'))]", "[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" ], "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Dynamic", "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPName'))]" }, "subnet": { "id": "[variables('subnetRef')]" } } } ] } }, { "type": "Microsoft.Compute/virtualMachines", "apiVersion": "2019-07-01", "name": "[parameters('vmName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" ], "properties": { "hardwareProfile": { "vmSize": "[parameters('vmSize')]" }, "osProfile": { "computerName": "[parameters('vmName')]", "adminUsername": "[parameters('adminUsername')]", "adminPassword": "[parameters('adminPassword')]" }, "storageProfile": { "imageReference": { "publisher": "MicrosoftWindowsServer", "offer": "WindowsServer", "sku": "[parameters('OSVersion')]", "version": "latest" }, "osDisk": { "createOption": "FromImage", "managedDisk": { "storageAccountType": "Standard_LRS" } }, "dataDisks": [ { "diskSizeGB": 1023, "lun": 0, "createOption": "Empty", "managedDisk": { "storageAccountType": "Standard_LRS" } } ] }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" } ] }, "diagnosticsProfile": { "bootDiagnostics": { "enabled": false, "storageUri": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))).primaryEndpoints.blob]" } } } }, { "type": "Microsoft.Compute/virtualMachines/extensions", "apiVersion": "2019-07-01", "name": "[concat(parameters('vmName'),'/', 'InstallWebServer')]", "location": "[parameters('location')]", "dependsOn": [ "[concat('Microsoft.Compute/virtualMachines/',parameters('vmName'))]" ], "properties": { "publisher": "Microsoft.Compute", "type": "CustomScriptExtension", "protectedSettings": {}, "typeHandlerVersion": "1.7", "autoUpgradeMinorVersion": true, "settings": { "fileUris": [ "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/tutorial-vm-extension/installWebServer.ps1" ], "commandToExecute": "powershell.exe -ExecutionPolicy Unrestricted -File installWebServer.ps1" } } } ], "outputs": { "hostname": { "type": "string", "value": "[reference(parameters('publicIPName')).dnsSettings.fqdn]" } } } ================================================ FILE: templates/~arm-templates/windows-vm-cse/azuredeploy.parameters.json ================================================ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "adminUsername": { "value": "tim" }, "adminPassword": { "value": "MyP@$$w0rd!!" }, "dnsLabelPrefix": { "value": "twvm1dns" }, "publicIpName": { "value": "twaz304pip1" }, "OSVersion": { "value": "2019-Datacenter" }, "vmSize": { "value": "Standard_B2ms" }, "vmName": { "value": "simple-vm" }, "nicPrefix": { "value": "vmnicprefix" }, "vnetName": { "value": "oreilly-vnet" }, "vnetAddressPrefix": { "value": "10.10.0.0/16" }, "subnetName": { "value": "workload" }, "subnetPrefix": { "value": "10.10.2.0/24" } } } ================================================ FILE: warner-AZ500.pptx ================================================ [File too large to display: 10.9 MB]