[AZ-104] Grand Labs - Nordvex Energia S.A.
Cumulative Real Deployment Environmentβ
Core Narrativeβ
Company: Nordvex Energia S.A. | Sector: Utilities (electrical energy distribution)
Nordvex operates 14 substations in two regions and has just ended a contract with a private data center. The board has approved the complete migration of infrastructure to Azure in 90 days. You have been hired as the cloud architect responsible for the implementation.
Each step corresponds to a real technical decision. The prefix for all resources is nordvex. Capture the IDs, IPs, and object names produced in each step β they will be required in subsequent steps.
Prerequisitesβ
Validate all tools below before starting Step 1.
| Tool | Minimum Version | Required in Steps | Verification |
|---|---|---|---|
| Azure CLI | 2.50+ | All | az --version |
| Bicep CLI | Any | 33β36 | az bicep install && az bicep version |
| Docker Desktop | 24+ | 45β46 | docker --version |
| AzCopy | v10+ | 25 | azcopy --version |
- π° Estimated cost for complete execution: USD 15β35
- β±οΈ Estimated total time: 12β16 hours distributed across multiple sessions
- π Turn off and deallocate VMs, VMSS, and Bastion when ending each session
- π Primary region: East US | DR region: Brazil South
| Resource | Estimated cost | Observation |
|---|---|---|
| Azure Bastion (Basic) | ~USD 0.19/h | Turn off after use |
| VM Standard_B4ms | ~USD 0.15/h | Deallocate between sessions |
| VMSS (2x B2s) | ~USD 0.10/h | Reduce to 0 instances between sessions |
| App Service P1v3 | ~USD 0.16/h | Scale down to F1 between sessions |
| Site Recovery | ~USD 0.16/VM/h | Disable after Step 81 |
Index by Exam Domainβ
| Domain | Steps |
|---|---|
| Domain 1 β Identity and Governance | 1β15 |
| Domain 2 β Storage | 16β32 |
| Domain 3 β Infrastructure as Code | 33β37 |
| Domain 4 β Compute and Containers | 38β48 |
| Domain 5 β App Service | 49β56 |
| Domain 6 β Networking | 57β69 |
| Domain 7 β Monitoring | 70β75 |
| Domain 8 β Backup and DR | 76β82 |
Domain 1 β Identity and Governanceβ
Step 1 β Create users and groups in Microsoft Entra IDβ
Context: Nordvex has three teams that need access to the Azure environment: IT operations, network engineering, and auditing. This is the foundation of all governance to come in subsequent steps.
Tasks:
[Portal] Create three users. Navigate to: Microsoft Entra ID β Users β New user β Create new user
| Field | User 1 | User 2 | User 3 |
|---|---|---|---|
| Display name | nordvex-ops-user | nordvex-net-user | nordvex-audit-user |
| User principal name | ops@<yourdomain> | net@<yourdomain> | audit@<yourdomain> |
| Password | Manually set | Manually set | Manually set |
| Force change password | No | No | No |
[Portal] Create two security groups. Navigate to: Microsoft Entra ID β Groups β New group
| Field | Group 1 | Group 2 |
|---|---|---|
| Group name | nordvex-ops-group | nordvex-net-group |
| Group type | Security | Security |
| Membership type | Assigned | Assigned |
| Members | nordvex-ops-user | nordvex-net-user |
[CLI] Capture the objectId of the three users and two groups:
az ad user list --filter "startswith(displayName,'nordvex')" --output table
az ad group list --filter "startswith(displayName,'nordvex')" --output table
Validation Criteria:
# Should return exactly 3 objects:
az ad user list --filter "startswith(displayName,'nordvex')" --output table
# Should return the objectId of nordvex-ops-user:
az ad group member list --group nordvex-ops-group --output table
In the Entra ID Users portal, all three users should appear with Account status = Enabled.
Step 2 β Manage user and group propertiesβ
Context: The HR department requires that all users have job title, department, and phone registered in the directory for internal auditing purposes.
Tasks:
[Portal] Edit each user. Navigate to: Microsoft Entra ID β Users β <user> β Properties β Job information
| User | Job title | Department | Business phone |
|---|---|---|---|
| nordvex-ops-user | Cloud Operator | IT | +55-31-0000-0001 |
| nordvex-net-user | Network Engineer | Networks | +55-31-0000-0002 |
| nordvex-audit-user | IT Auditor | Auditing | +55-31-0000-0003 |
[CLI] Update the usageLocation for the three users via Microsoft Graph:
az rest --method PATCH \
--url "https://graph.microsoft.com/v1.0/users/<objectId>" \
--body '{"usageLocation": "BR"}'
# Repeat for all three users
[Portal] Add description to the nordvex-ops-group group. Navigate to: Microsoft Entra ID β Groups β nordvex-ops-group β Properties
Description: Nordvex Energia cloud operators group
Validation Criteria:
az ad user show --id <objectId-ops-user> --query "{dept:department, location:usageLocation}"
# Expected: {"dept": "IT", "location": "BR"}
Step 3 β Manage licenses in Microsoft Entra IDβ
Context: Nordvex has purchased Microsoft 365 Business Premium licenses for the IT team. Finance requires that the group be the assignment vehicle, not individual users.
Tasks:
- [Portal] Check available licenses. Navigate to:
Microsoft Entra ID β Billing β Licenses β All products - [Portal] Assign license to group. Navigate to:
Microsoft Entra ID β Groups β nordvex-ops-group β Licenses β Assignments - [Portal] Check inheritance in user. Navigate to:
Microsoft Entra ID β Users β nordvex-ops-user β Licenses
Validation Criteria:
- In the
nordvex-ops-user β Licensesprofile, the license should appear with origin "Inherited from group". - The user
nordvex-audit-user(not in the group) should not have a license assigned.
Step 4 β Manage external usersβ
Context: Nordvex has hired an external consultant from Voltec Consultoria. They need temporary read access without having an internal account in the directory.
Tasks:
- [Portal] Invite external user. Navigate to:
Microsoft Entra ID β Users β New user β Invite external user- Display name:
nordvex-ext-voltec - Message: Access to Nordvex Energia's Azure migration project
- Display name:
- [Portal] Confirm that
User type = Guest. Navigate to:Microsoft Entra ID β Users β nordvex-ext-voltec β Properties - [CLI] Confirm:
az ad user list --filter "userType eq 'Guest'" --output table
# Should return at least 1 object with displayName = nordvex-ext-voltec
Step 5 β Configure self-service password reset (SSPR)β
Context: The helpdesk logs 40 monthly password reset tickets. Enabling SSPR in the operations group scope reduces this volume.
Tasks:
- [Portal] Enable SSPR. Navigate to:
Microsoft Entra ID β Password reset β Properties- Self service password reset enabled: Selected
- Add
nordvex-ops-groupas scope
- [Portal] Configure methods. Navigate to:
Microsoft Entra ID β Password reset β Authentication methods- Number of methods required: 1
- Enable: Email and Mobile phone
- [Portal] Configure registration. Navigate to:
Microsoft Entra ID β Password reset β Registration- Require users to register when signing in: Yes
- Reconfirmation days: 180
Validation Criteria:
Password reset β Properties: scope should display Selected withnordvex-ops-grouplisted.Authentication methods: at least 2 methods enabled.Registration: "Require users to register" = Yes.
Step 6 β Manage Azure built-in rolesβ
Context: Security policy determines: operations = Contributor, networks = Reader, auditor = Billing Reader.
Tasks:
- [Portal] Create the main resource group. Navigate to:
Resource groups β Create- Name:
nordvex-rg| Region:East US
- Name:
- [Portal] Assign Contributor to group. Navigate to:
nordvex-rg β Access control (IAM) β Add role assignment- Role: Contributor | Assignee:
nordvex-ops-group
- Role: Contributor | Assignee:
- [CLI] Assign Reader to networks group:
az role assignment create \
--role "Reader" \
--assignee-object-id <objectId-net-group> \
--scope /subscriptions/<subscriptionId>/resourceGroups/nordvex-rg \
--assignee-principal-type Group
- [Portal] Assign Billing Reader to auditor. Navigate to:
Subscriptions β <subscription> β Access control (IAM) β Add role assignment- Role: Billing Reader | Assignee:
nordvex-audit-user
- Role: Billing Reader | Assignee:
Validation Criteria:
az role assignment list --resource-group nordvex-rg --output table
# Should contain: nordvex-ops-group (Contributor) and nordvex-net-group (Reader)
az role assignment list --scope /subscriptions/<subscriptionId> \
--assignee <objectId-audit-user> --output table
# Should return: Billing Reader for nordvex-audit-user
Step 7 β Assign roles at different scopesβ
Context: Demonstrate the principle of least privilege by scope: Contributor in production, Reader in development.
Tasks:
- [CLI] Create the development resource group:
az group create --name nordvex-dev-rg --location eastus
- [Portal] Assign Reader to
nordvex-ops-userinnordvex-dev-rg. Navigate to:nordvex-dev-rg β Access control (IAM) β Add role assignment - [CLI] List all assignments across all scopes:
az role assignment list --assignee <objectId-ops-user> --all --output table
Validation Criteria:
- The
--allcommand should return at least 2 entries with different scopes. - Scope
/resourceGroups/nordvex-rg: Contributor (inherited from group). - Scope
/resourceGroups/nordvex-dev-rg: Reader (direct assignment).
Step 8 β Interpret access assignmentsβ
Context: The auditor requested a report of who has access to what in the production resource group.
Tasks:
- [Portal] Check effective access. Navigate to:
nordvex-rg β Access control (IAM) β Check access β Search nordvex-ops-user - [Portal] View assignments. Navigate to:
nordvex-rg β Access control (IAM) β Role assignments β Type: All - [CLI] Capture all assignments including inherited:
az role assignment list --resource-group nordvex-rg --include-inherited --output table
Validation Criteria:
- Check access for
nordvex-ops-usershould display Contributor as effective permission. - The CLI command should return at least 3 distinct entries for
nordvex-rg.
Step 9 β Implement and manage Azure Policyβ
Context: The compliance team requires that all resources be in East US or Brazil South regions and that no resource be created without the CostCenter tag.
Tasks:
- [Portal] Assign location policy. Navigate to:
Policy β Assignments β Assign policy- Scope:
nordvex-rg - Policy definition: "Allowed locations"
- Allowed locations:
eastus,brazilsouth
- Scope:
- [Portal] Assign tag policy. Navigate to:
Policy β Assignments β Assign policy- Policy definition: "Require a tag and its value"
- Tag name:
CostCenter| Tag value:NordvexProd
- [CLI] Confirm assignments:
az policy assignment list --resource-group nordvex-rg --output table
# Should return at least 2 entries
- [Portal] Try to create a Storage Account in
West USwithinnordvex-rgand observe the policy violation error.
Step 10 β Configure resource locksβ
Context: No team member should be able to accidentally delete the production resource group, even with Contributor permissions.
Tasks:
- [Portal] Add the lock. Navigate to:
nordvex-rg β Settings β Locks β Add- Lock name:
nordvex-lock-delete| Lock type: Delete - Notes:
Production protected against accidental deletion
- Lock name:
- [CLI] Confirm:
az lock list --resource-group nordvex-rg --output table
# lockType = CanNotDelete, name = nordvex-lock-delete
- [Portal] Logged in as
nordvex-ops-user(Contributor), try to deletenordvex-rgand observe the lock.
Step 11 β Apply and manage tags on resourcesβ
Context: The CFO requires granular cost visibility by cost center and environment.
Tasks:
- [CLI] Apply the three tags to the resource group:
az group update --name nordvex-rg \
--tags CostCenter=NordvexProd Environment=Production ManagedBy=CloudOps
- [Portal] Confirm tags. Navigate to:
nordvex-rg β Tags - [CLI] Check tags of resources within the group:
az resource list --resource-group nordvex-rg --query "[].{name:name, tags:tags}" --output json
Validation Criteria:
az group show --name nordvex-rg --query tags
# Expected:
# {
# "CostCenter": "NordvexProd",
# "Environment": "Production",
# "ManagedBy": "CloudOps"
# }
Step 12 β Manage resource groupsβ
Context: Nordvex decided to separate network resources into a dedicated resource group, following the landing zone architecture.
Tasks:
- [CLI] Create the network resource group:
az group create --name nordvex-net-rg --location eastus \
--tags CostCenter=NordvexProd Environment=Production ManagedBy=CloudOps
- [Portal] Create a basic VNet within
nordvex-rg. Navigate to:Virtual networks β Create- Name:
nordvex-vnet-temp| Resource group:nordvex-rg| Address space:10.0.0.0/16
- Name:
- [Portal] Move the VNet to
nordvex-net-rg. Navigate to:nordvex-vnet-temp β Overview β Move β Move to another resource group
Validation Criteria:
az group list --query "[?starts_with(name,'nordvex')]" --output table
# Should return: nordvex-rg, nordvex-net-rg, nordvex-dev-rg
az network vnet list --resource-group nordvex-net-rg --output table
# Should return nordvex-vnet-temp after the move
Step 13 β Manage subscriptionsβ
Context: The finance team needs to ensure that subscriptions used in the project have correct metadata. Tasks:
- [CLI] List subscriptions:
az account list --output table
- [Portal] Rename the subscription. Navigate to:
Subscriptions β <subscription> β Overview β Rename- New name:
Nordvex-Production
- New name:
- [CLI] Set the active subscription and confirm:
az account set --subscription <id>
az account show --query "{name:name, id:id, tenantId:tenantId}" --output json
Step 14 β Managing costs with alerts, budgets and Azure Advisorβ
Context: The approved budget for the first quarter is USD 500. The finance team needs automatic alerts at 80% and 100%.
Tasks:
- [Portal] Create the budget. Navigate to:
Cost Management + Billing β Cost Management β Budgets β Add- Scope:
nordvex-rg| Name:nordvex-budget-q1| Amount: USD 500 | Reset period: Monthly - Alert at 80%: email to
nordvex-ops-user
- Scope:
- [Portal] Review recommendations. Navigate to:
Advisor β Cost - [Portal] Add 100% alert to the same budget.
Validation Criteria:
- The budget
nordvex-budget-q1should appear with Status = Active. - At least 2 threshold alerts configured (80% and 100%).
Step 15 β Configure management groupsβ
Context: Nordvex has two subscriptions and needs to apply corporate policies centrally.
Tasks:
- [Portal] Create the management group. Navigate to:
Management groups β Start using management groups β Add management group- Management group ID:
nordvex-mg - Display name:
Nordvex Management Group
- Management group ID:
- [Portal] Move the production subscription to the group. Navigate to:
nordvex-mg β Add subscription - [CLI] Confirm the structure:
az account management-group show --name nordvex-mg --expand --recurse --output json
# Should return the group with at least 1 child subscription in "children"
Domain 2 β Storageβ
Step 16 β Configure Azure Storage firewalls and virtual networksβ
Context: The central storage account for logs should have restricted access to the virtual network, blocking public access by default.
Tasks:
- [CLI] Create the main storage account:
az storage account create \
--name nordvexstg \
--resource-group nordvex-rg \
--location eastus \
--sku Standard_LRS \
--kind StorageV2 \
--allow-blob-public-access false \
--tags CostCenter=NordvexProd Environment=Production
- [Portal] Restrict network access. Navigate to:
nordvexstg β Security + networking β Networking β Firewalls and virtual networks- Public network access: Enabled from selected virtual networks and IP addresses
- Add
nordvex-vnet-tempas allowed network
- [Portal] Add your workstation's public IP in the Address ranges section.
Validation Criteria:
az storage account show --name nordvexstg --resource-group nordvex-rg \
--query "networkRuleSet" --output json
# defaultAction should be "Deny"
# The VNet should appear in virtualNetworkRules
Step 17 β Create and use SAS tokensβ
Context: The substation telemetry system needs to upload logs to a Blob container without using account keys.
Tasks:
- [Portal] Create the log container. Navigate to:
nordvexstg β Data storage β Containers β + Container- Name:
nordvex-logs| Public access level: Private
- Name:
- [Portal] Generate the SAS token. Navigate to:
nordvexstg β Security + networking β Shared access signature
| Parameter | Value |
|---|---|
| Allowed services | Blob only |
| Allowed resource types | Object only |
| Allowed permissions | Read, Write |
| Expiry | 24 hours from now |
| Allowed protocols | HTTPS only |
- [CLI] Upload a test file:
az storage blob upload \
--account-name nordvexstg \
--container-name nordvex-logs \
--name teste.log \
--file ./teste.log \
--sas-token "<token-generated-in-portal>"
Validation Criteria:
az storage blob list --account-name nordvexstg \
--container-name nordvex-logs --sas-token "<token>" --output table
# Should return the test file
Step 18 β Configure stored access policiesβ
Context: Nordvex needs to revoke SAS access without waiting for expiration, using a Stored Access Policy.
Tasks:
- [Portal] Create the policy. Navigate to:
nordvexstg β Containers β nordvex-logs β Access policy β Add policy- Identifier:
nordvex-log-policy| Permissions: Read, Write | Expiry: 7 days
- Identifier:
- [CLI] Generate a SAS linked to the policy:
az storage container generate-sas \
--account-name nordvexstg \
--name nordvex-logs \
--policy-name nordvex-log-policy \
--output tsv
Validation Criteria:
- The policy
nordvex-log-policyshould appear listed in Access policy of thenordvex-logscontainer. - The generated SAS token should contain the parameter
si=nordvex-log-policyin the URL.
Step 19 β Manage access keysβ
Context: The security team detected that the primary key was used in a legacy script. Immediate rotation is mandatory.
Tasks:
- [Portal] View the keys. Navigate to:
nordvexstg β Security + networking β Access keys - [Portal] Regenerate key1. Click Rotate key next to key1. Capture the new value.
- [CLI] Confirm:
az storage account keys list \
--account-name nordvexstg \
--resource-group nordvex-rg \
--output table
Validation Criteria:
- The command should return two objects: key1 and key2.
- The operation should appear in the Activity log of
nordvex-rgas a"regenerateKey"event.
Step 20 β Configure identity-based access for Azure Filesβ
Context: The networking department needs an SMB share with Microsoft Entra ID identity-based authentication.
Tasks:
- [Portal] Create the file share. Navigate to:
nordvexstg β Data storage β File shares β + File share- Name:
nordvex-share| Quota: 50 GiB | Tier: Transaction optimized
- Name:
- [Portal] Enable Entra ID authentication. Navigate to:
nordvexstg β Data management β Configuration β Identity-based access β Microsoft Entra Kerberos - [Portal] Assign SMB role. Navigate to:
nordvexstg β File shares β nordvex-share β Access control (IAM) β Add role assignment- Role: Storage File Data SMB Share Contributor | Assignee:
nordvex-net-group
- Role: Storage File Data SMB Share Contributor | Assignee:
Validation Criteria:
az storage share-rm show --storage-account nordvexstg \
--resource-group nordvex-rg --name nordvex-share --output json
# enabledProtocols should contain SMB
Step 21 β Create archive storage accountβ
Context: Nordvex needs a secondary account for long-term archival of billing data with geo-redundancy.
Tasks:
- [CLI] Create the archive account:
az storage account create \
--name nordvexarchive \
--resource-group nordvex-rg \
--location brazilsouth \
--sku Standard_GRS \
--kind StorageV2 \
--access-tier Cool \
--tags CostCenter=NordvexProd Environment=Production
- [Portal] Confirm. Navigate to:
nordvexarchive β Overview- Redundancy: GRS (Geo-redundant storage) | Access tier: Cool
Validation Criteria:
az storage account show --name nordvexarchive --resource-group nordvex-rg \
--query "{sku:sku.name, kind:kind, accessTier:accessTier}" --output json
# Expected: {"sku": "Standard_GRS", "kind": "StorageV2", "accessTier": "Cool"}
Step 22 β Configure Azure Storage redundancyβ
Context: The business continuity team determined that nordvexstg needs to be upgraded to ZRS.
Tasks:
- [Portal] Change redundancy. Navigate to:
nordvexstg β Data management β Redundancy- Change from LRS to Zone-redundant storage (ZRS)
Validation Criteria:
az storage account show --name nordvexstg --resource-group nordvex-rg \
--query "sku.name" --output tsv
# Should return: Standard_ZRS
Step 23 β Configure object replicationβ
Context: Logs from the nordvex-logs container should be automatically replicated to the archive account.
Tasks:
- [Portal] Enable versioning on both accounts (prerequisite for replication).
nordvexstg β Data protection β Enable versioning for blobs- Repeat for
nordvexarchive
- [Portal] Create replication rule. Navigate to:
nordvexstg β Data management β Object replication β Create replication rules- Destination account:
nordvexarchive - Source container:
nordvex-logs - Destination container:
nordvex-logs-replica(create new)
- Destination account:
Validation Criteria:
- Object replication in
nordvexstgshould display at least 1 policy with status Enabled. - The container
nordvex-logs-replicashould exist innordvexarchive.
Step 24 β Configure storage account encryption (CMK)β
Context: The legal department requires customer-managed keys (CMK) for regulatory compliance.
Tasks:
- [Portal] Create the Key Vault. Navigate to:
Key vaults β Create- Name:
nordvex-kv| Resource group:nordvex-rg| Region: East US | Soft delete: Enabled
- Name:
- [Portal] Create the key. Navigate to:
nordvex-kv β Objects β Keys β Generate/Import- Name:
nordvex-storage-key| Key type: RSA | Key size: 2048
- Name:
- [Portal] Configure CMK. Navigate to:
nordvexstg β Security + networking β Encryption- Encryption type: Customer-managed keys
- Key vault:
nordvex-kv| Key:nordvex-storage-key
Validation Criteria:
az storage account show --name nordvexstg --resource-group nordvex-rg \
--query "encryption.keySource" --output tsv
# Should return: Microsoft.Keyvault
Step 25 β Manage data with AzCopyβ
Context: The operations team needs to bulk transfer historical log files to the nordvex-logs container.
AzCopy v10+ installed locally. Check with: azcopy --version
Tasks:
- [CLI] Upload via AzCopy:
azcopy copy "./logs-locais/*" \
"https://nordvexstg.blob.core.windows.net/nordvex-logs?<SAS-token>" \
--recursive
- [Portal] Confirm the files. Navigate to:
nordvexstg β Storage browser β Blob containers β nordvex-logs - [CLI] List objects:
azcopy list "https://nordvexstg.blob.core.windows.net/nordvex-logs?<SAS-token>"
Step 26 β Create and configure file share in Azure Filesβ
Context: The nordvex-share file share needs a working directory to organize substation files.
Tasks:
- [Portal] Create a directory. Navigate to:
nordvexstg β File shares β nordvex-share β + Add directory- Name:
subestacoes
- Name:
- [Portal] Upload a test file to the
subestacoesdirectory. - [CLI] Confirm:
az storage file list \
--share-name nordvex-share \
--account-name nordvexstg \
--path subestacoes \
--output table
# Should return at least 1 file
Step 27 β Create and configure container in Azure Blob Storageβ
Context: Nordvex needs a container to store backup images of substation configurations.
Tasks:
- [Portal] Create the backup container. Navigate to:
nordvexstg β Data storage β Containers β + Container- Name:
nordvex-backups| Public access level: Private
- Name:
- [CLI] Upload using the account key captured in Step 19:
az storage blob upload \
--account-name nordvexstg \
--container-name nordvex-backups \
--name backup-test.img \
--file ./backup-test.img \
--account-key "<key1-captured-in-step-19>"
Validation Criteria:
az storage container list --account-name nordvexstg --output table
# Should return: nordvex-logs, nordvex-backups
Step 28 β Configure storage tiersβ
Context: Backups older than 30 days should go to Cool and after 90 days to Archive, reducing costs.
Tasks:
- [Portal] Change a blob tier manually. Navigate to:
nordvexstg β Storage browser β Blob containers β nordvex-backups β <blob> β Change tier β Cool - [CLI] Move a blob to Archive:
az storage blob set-tier \
--account-name nordvexstg \
--container-name nordvex-backups \
--name backup-test.img \
--tier Archive
Validation Criteria:
az storage blob show --account-name nordvexstg \
--container-name nordvex-backups --name backup-test.img \
--query "properties.blobTier" --output tsv
# Should return: Archive
Step 29 β Configure soft delete for blobs and containersβ
Context: Soft delete should be enabled on all production accounts with 14-day retention.
Tasks:
- [Portal] Enable soft delete for blobs. Navigate to:
nordvexstg β Data protection β Enable soft delete for blobs- Retention period: 14 days
- [Portal] Enable soft delete for containers. Navigate to:
nordvexstg β Data protection β Enable soft delete for containers- Retention period: 7 days
- [CLI] Confirm:
az storage account blob-service-properties show \
--account-name nordvexstg --resource-group nordvex-rg \
--query "{blobSoftDelete:deleteRetentionPolicy, containerSoftDelete:containerDeleteRetentionPolicy}"
# blobSoftDelete: enabled=true, days=14
# containerSoftDelete: enabled=true, days=7
Step 30 β Configure snapshots and soft delete for Azure Filesβ
Context: The nordvex-share file share should have protection against accidental deletion.
The complete Azure Files backup via Recovery Services Vault will be configured in Step 76, when the vault will be created. For now, just enable soft delete and create a manual snapshot as per the tasks below. After creating the vault in Step 76, you can return here and enable integrated backup of the file share.
Tasks:
- [Portal] Enable soft delete for file shares. Navigate to:
nordvexstg β Data protection β Enable soft delete for file shares- Retention period: 14 days
- [Portal] Create a manual snapshot. Navigate to:
nordvexstg β File shares β nordvex-share β Operations β Snapshots β Add snapshot - [Portal] Confirm the snapshot. Navigate to:
nordvex-share β Operations β Snapshots
Validation Criteria:
- The Snapshots blade should list at least 1 snapshot with valid timestamp.
- Account Data protection should show soft delete for file shares enabled with 14 days.
Step 31 β Configure blob lifecycle managementβ
Context: Nordvex wants to automate tier transition and blob expiration in the nordvex-logs container.
Tasks:
- [Portal] Create the lifecycle rule. Navigate to:
nordvexstg β Data management β Lifecycle management β Add a rule- Rule name:
nordvex-log-lifecycle - Apply rule to: Blobs in
nordvex-logs
- Rule name:
| Condition | Action |
|---|---|
| Blobs older than 30 days | Move to Cool storage |
| Blobs older than 90 days | Move to Archive storage |
| Blobs older than 365 days | Delete the blob |
- [CLI] Confirm:
az storage account management-policy show \
--account-name nordvexstg \
--resource-group nordvex-rg
# Should contain nordvex-log-lifecycle with 3 actions
Step 32 β Configure blob versioningβ
Context: Versioning was enabled as a prerequisite in Step 23. Now you must validate the behavior.
Tasks:
- [Portal] Confirm that versioning is enabled. Navigate to:
nordvexstg β Data protection β Enable versioning for blobs - [CLI] Upload the same file twice with different content:
echo "Version 1" > version-file.txt
az storage blob upload --account-name nordvexstg \
--container-name nordvex-logs --name version-file.txt \
--file ./version-file.txt --overwrite
echo "Version 2" > version-file.txt
az storage blob upload --account-name nordvexstg \
--container-name nordvex-logs --name version-file.txt \
--file ./version-file.txt --overwrite
- [CLI] List the versions:
az storage blob list --account-name nordvexstg \
--container-name nordvex-logs --include v --output table
# Should return at least 2 entries for version-file.txt with distinct versionId
Domain 3 β Infrastructure as Code (IaC)β
az bicep install && az bicep version β Execute before starting this section.
Step 33 β Interpret ARM templates and Bicep filesβ
Context: The platform team received a legacy ARM template from a vendor. Before executing, you must analyze the declared parameters, resources, and dependencies.
Tasks:
- [Portal] Export the ARM template from a previous deployment. Navigate to:
nordvex-rg β Deployments β <deployment> β Template β Download - [IaC] Analyze the exported template and identify:
- How many resources are declared in the
resourcessection - Which parameters have
defaultValue - Which explicit dependencies (
dependsOn) are present
- How many resources are declared in the
- [CLI] Convert to Bicep:
az bicep decompile --file template.json
az bicep build --file template.bicep
Step 34 β Modify existing ARM templateβ
Context: The ARM template needs to be modified to add the tag CostCenter: NordvexProd to all resources.
Tasks:
- [IaC] Add the
tagsblock withCostCenter: NordvexProdto each resource in theresourcessection. - [IaC] Add an
environmentparameter of typestringwithdefaultValue: "Production"and use it as the value for theEnvironmenttag. - [CLI] Validate:
az deployment group validate \
--resource-group nordvex-rg \
--template-file modified-template.json
# Should return "provisioningState": "Succeeded"
Step 35 β Modify existing Bicep fileβ
Context: The Bicep file needs to be expanded to include an additional storage account.
Tasks:
- [IaC] Add a new storage resource to the
.bicepfile:
resource nordvexBicepStorage 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: 'nordvexbicep'
location: location
sku: { name: 'Standard_LRS' }
kind: 'StorageV2'
tags: { CostCenter: 'NordvexProd', Environment: environment }
}
output storageAccountId string = nordvexBicepStorage.id
- [CLI] Validate:
az bicep build --file template.bicep
Step 36 β Deploy resources with Bicep templateβ
Context: With the Bicep template validated, execute the actual deployment to the production resource group.
Tasks:
- [CLI] Execute the deployment:
az deployment group create \
--resource-group nordvex-rg \
--template-file template.bicep \
--parameters environment=Production \
--name nordvex-bicep-deploy
- [CLI] Capture the output:
az deployment group show \
--resource-group nordvex-rg \
--name nordvex-bicep-deploy \
--query "properties.provisioningState" --output tsv
# Should return: Succeeded
Step 37 β Export deployment as ARM templateβ
Context: The DR team needs a versioned template of the current environment to recreate the infrastructure in case of disaster.
Tasks:
- [Portal] Export the template for the entire group. Navigate to:
nordvex-rg β Automation β Export template β Download - [CLI] Export via CLI:
az group export --name nordvex-rg > nordvex-rg-export.json
Validation Criteria:
- The exported file must contain at least 3 distinct resources in the
resourcessection. - Valid JSON verification:
cat nordvex-rg-export.json | python3 -m json.tool
Domain 4 β Compute and Containersβ
Docker Desktop installed and running. Verify with: docker --version
Step 38 β Create a virtual machineβ
Context: Nordvex's SCADA system needs a Windows Server VM to run legacy substation monitoring software.
Tasks:
- [CLI] Create the SCADA VM:
az vm create \
--name nordvex-vm-scada \
--resource-group nordvex-rg \
--location eastus \
--image Win2022Datacenter \
--size Standard_B2s \
--admin-username nordvexadmin \
--admin-password "<secure-password>" \
--os-disk-sku Premium_LRS \
--vnet-name nordvex-vnet-temp \
--vnet-resource-group nordvex-net-rg \
--subnet default \
--tags CostCenter=NordvexProd Environment=Production
- [Portal] Capture the private IP. Navigate to:
nordvex-vm-scada β Networking β Network interface
Validation Criteria:
az vm show --name nordvex-vm-scada --resource-group nordvex-rg \
--show-details --query "powerState" --output tsv
# Should return: VM running
Step 39 β Configure encryption at host for VMsβ
Context: The compliance requirement mandates that all temporary data on the host be encrypted.
Tasks:
- [CLI] Register the feature (once per subscription):
az feature register --name EncryptionAtHost --namespace Microsoft.Compute
# Wait until it returns "state": "Registered"
az feature show --name EncryptionAtHost --namespace Microsoft.Compute
- [CLI] Stop and deallocate the VM:
az vm deallocate --name nordvex-vm-scada --resource-group nordvex-rg
- [CLI] Enable encryption at host:
az vm update --name nordvex-vm-scada --resource-group nordvex-rg \
--set securityProfile.encryptionAtHost=true
Validation Criteria:
az vm show --name nordvex-vm-scada --resource-group nordvex-rg \
--query "securityProfile.encryptionAtHost" --output tsv
# Should return: True
Step 40 β Move VM to another resource groupβ
Context: The SCADA VM should be moved to nordvex-net-rg, along with the network resources.
Tasks:
- [Portal] Move the VM. Navigate to:
nordvex-vm-scada β Overview β Move β Move to another resource group- Destination resource group:
nordvex-net-rg
- Destination resource group:
Validation Criteria:
az vm list --resource-group nordvex-net-rg --output table
# Should display nordvex-vm-scada
az vm list --resource-group nordvex-rg --output table
# Should not display nordvex-vm-scada
Step 41 β Manage VM sizesβ
Context: The SCADA software was updated and requires more memory. The VM needs to be resized to Standard_B4ms.
Tasks:
- [CLI] List available sizes:
az vm list-vm-resize-options --name nordvex-vm-scada --resource-group nordvex-net-rg --output table
- [Portal] Resize. Navigate to:
nordvex-vm-scada β Availability + scale β Size β Standard_B4ms β Resize
The VM will be automatically restarted during resizing.
Validation Criteria:
az vm show --name nordvex-vm-scada --resource-group nordvex-net-rg \
--query "hardwareProfile.vmSize" --output tsv
# Should return: Standard_B4ms
Step 42 β Manage VM disksβ
Context: The SCADA software requires a dedicated 128 GB data disk for telemetry history files.
Tasks:
- [Portal] Add data disk. Navigate to:
nordvex-vm-scada β Settings β Disks β + Create and attach a new disk
| Parameter | Value |
|---|---|
| Disk name | nordvex-disk-scada |
| Size | 128 GiB |
| Disk type | Premium SSD |
| Host caching | Read-only |
Validation Criteria:
az disk show --name nordvex-disk-scada --resource-group nordvex-net-rg \
--query "{size:diskSizeGb, sku:sku.name}" --output json
# Expected: {"size": 128, "sku": "Premium_LRS"}
Step 43 β Deploy VMs in availability zones and availability setsβ
Context: The load dispatch system requires high availability with a second VM in a different zone.
Tasks:
- [CLI] Create the dispatch VM in zone 1:
az vm create \
--name nordvex-vm-dispatch \
--resource-group nordvex-net-rg \
--location eastus \
--zone 1 \
--image Ubuntu2204 \
--size Standard_B2s \
--admin-username nordvexadmin \
--generate-ssh-keys \
--tags CostCenter=NordvexProd
- [CLI] Create an availability set:
az availability-set create \
--name nordvex-avset \
--resource-group nordvex-net-rg \
--location eastus \
--platform-fault-domain-count 2 \
--platform-update-domain-count 5
Validation Criteria:
az vm show --name nordvex-vm-dispatch --resource-group nordvex-net-rg \
--query "zones" --output tsv
# Should return: 1
Step 44 β Deploy and configure Azure Virtual Machine Scale Setsβ
Context: The internal web portal needs automatic scaling based on CPU load.
Tasks:
- [Portal] Create the VMSS. Navigate to:
Virtual machine scale sets β Create
| Parameter | Value |
|---|---|
| Name | nordvex-vmss |
| Resource group | nordvex-rg |
| Region | East US |
| Image | Ubuntu Server 22.04 LTS |
| Size | Standard_B2s |
| Initial count | 2 |
| Orchestration mode | Uniform |
- [Portal] Configure autoscale. Navigate to:
nordvex-vmss β Availability + scale β Scaling- Scale-out: CPU > 75% for 5 min β add 1 instance
- Scale-in: CPU < 25% for 5 min β remove 1 instance
- Minimum: 2 | Maximum: 5
Step 45 β Create and manage an Azure Container Registryβ
Context: The development team needs a private registry for the billing system image.
Docker Desktop must be installed and running.
Tasks:
- [CLI] Create the Container Registry:
az acr create \
--name nordvexacr \
--resource-group nordvex-rg \
--sku Basic \
--location eastus
- [CLI] Authenticate and push:
az acr login --name nordvexacr
docker pull nginx:alpine
docker tag nginx:alpine nordvexacr.azurecr.io/billing:v1
docker push nordvexacr.azurecr.io/billing:v1
Validation Criteria:
az acr repository list --name nordvexacr --output table
# Should return: billing
Step 46 β Provision container with Azure Container Instancesβ
Context: Quick validation of the billing system image without the complexity of Kubernetes.
Tasks:
- [CLI] Create the instance:
az container create \
--name nordvex-aci-billing \
--resource-group nordvex-rg \
--image nordvexacr.azurecr.io/billing:v1 \
--registry-login-server nordvexacr.azurecr.io \
--registry-username $(az acr credential show -n nordvexacr --query username -o tsv) \
--registry-password $(az acr credential show -n nordvexacr --query "passwords[0].value" -o tsv) \
--cpu 1 --memory 1.5 \
--ports 80 \
--dns-name-label nordvexbilling \
--location eastus
Validation Criteria:
az container show --name nordvex-aci-billing --resource-group nordvex-rg \
--query "instanceView.state" --output tsv
# Should return: Running
Step 47 β Provision container with Azure Container Appsβ
Context: After validation in ACI, the billing system goes to Container Apps with automatic scaling.
Tasks:
- [CLI] Create the environment and app:
az containerapp env create \
--name nordvex-cae \
--resource-group nordvex-rg \
--location eastus
az containerapp create \
--name nordvex-ca-billing \
--resource-group nordvex-rg \
--environment nordvex-cae \
--image nordvexacr.azurecr.io/billing:v1 \
--cpu 0.5 --memory 1Gi \
--ingress external --target-port 80 \
--min-replicas 1 --max-replicas 3
Validation Criteria:
az containerapp show --name nordvex-ca-billing --resource-group nordvex-rg \
--query "properties.runningStatus" --output tsv
# Should return: Running
Step 48 β Manage container scalingβ
Context: The Container App needs scaling rules based on HTTP requests.
Tasks:
- [Portal] Configure scaling. Navigate to:
nordvex-ca-billing β Application β Scale and replicas- Scale rule type: HTTP concurrent requests
- Concurrent requests limit: 10 | Min replicas: 1 | Max replicas: 5
- [CLI] List active revisions:
az containerapp revision list --name nordvex-ca-billing --resource-group nordvex-rg --output table
Domain 5 β App Serviceβ
Step 49 β Provision App Service planβ
Context: The customer self-service portal will be hosted on Azure App Service.
App Service P1v3 generates ~USD 0.16/h. Scale down to F1 between sessions if needed.
Tasks:
- [CLI] Create the App Service Plan:
az appservice plan create \
--name nordvex-asp \
--resource-group nordvex-rg \
--sku P1v3 \
--is-linux \
--location eastus
Validation Criteria:
az appservice plan show --name nordvex-asp --resource-group nordvex-rg \
--query "{sku:sku.name, os:kind}" --output json
# Expected: {"sku": "P1v3", "os": "linux"}
Step 50 β Configure scaling for App Service Planβ
Context: The plan should automatically scale between 1 and 3 instances based on CPU usage.
Tasks:
- [Portal] Configure autoscale. Navigate to:
nordvex-asp β Settings β Scale out (App Service plan)- Scale mode: Custom autoscale
- Minimum: 1 | Maximum: 3 | Default: 1
- Scale-out: CPU > 70% for 10 min β add 1 instance
- Scale-in: CPU < 30% for 10 min β remove 1 instance
Step 51 β Create an App Serviceβ
Context: Create and associate the customer portal web application to the nordvex-asp plan.
Tasks:
- [CLI] Create the Web App:
az webapp create \
--name nordvex-webapp \
--resource-group nordvex-rg \
--plan nordvex-asp \
--runtime "NODE:20-lts"
# The name must be globally unique β add suffix if necessary
- [CLI] Get the URL:
az webapp show --name nordvex-webapp --resource-group nordvex-rg \
--query "defaultHostName" --output tsv
# Access https://<defaultHostName> β should display the App Service default page
Step 52 β Configure certificates and TLS for App Serviceβ
Context: The portal must force HTTPS with TLS 1.2 as minimum version.
Tasks:
- [Portal] Force HTTPS. Navigate to:
nordvex-webapp β Settings β Configuration β General settings- HTTPS Only: On
- [Portal] Set minimum TLS. Navigate to:
nordvex-webapp β Settings β TLS/SSL settings- Minimum TLS Version: 1.2
Validation Criteria:
az webapp show --name nordvex-webapp --resource-group nordvex-rg \
--query "{httpsOnly:httpsOnly, minTls:siteConfig.minTlsVersion}" --output json
# Expected: {"httpsOnly": true, "minTls": "1.2"}
Step 53 β Map custom DNS for App Serviceβ
Context: The portal should be accessible through the portal.nordvex.internal domain. You should document the required DNS records.
Tasks:
- [Portal] Access the domains blade. Navigate to:
nordvex-webapp β Settings β Custom domains β Add custom domain - [Portal] Observe and document the required DNS records:
- Verification TXT record
- App Service IP address for A record
- [Portal] If you have a domain for testing, complete the mapping. Otherwise, document the displayed values.
Step 54 β Configure backup for App Serviceβ
Context: Weekly automatic backups should be configured using the existing storage account.
Tasks:
- [Portal] Configure backup. Navigate to:
nordvex-webapp β Settings β Backups β Configure- Storage account:
nordvexstg| Container:nordvex-backups - Backup frequency: Weekly | Time: 02:00 UTC | Retention: 4 backups
- Storage account:
- [Portal] Execute immediate backup:
Backups β Backup now
Validation Criteria:
- The Backups blade should display at least 1 entry with Succeeded status.
- The
nordvex-backupscontainer should contain the generated backup files.
Step 55 β Configure networking for App Serviceβ
Context: The portal should not be accessible from the public internet. Access should be restricted to VNet via VNet Integration.
Tasks:
- [Portal] Add subnet to VNet. Navigate to:
nordvex-vnet-temp β Subnets β + Subnet- Name:
nordvex-snet-app| Address range:10.0.2.0/24
- Name:
- [Portal] Configure VNet Integration. Navigate to:
nordvex-webapp β Settings β Networking β VNet integration β Add VNet integration- Virtual network:
nordvex-vnet-temp| Subnet:nordvex-snet-app
- Virtual network:
- [CLI] Confirm:
az webapp vnet-integration list \
--name nordvex-webapp \
--resource-group nordvex-rg \
--output table
Step 56 β Configure deployment slots for App Serviceβ
Context: Nordvex adopts blue-green deployment. App Service should have a staging slot for validation before promotion to production.
Tasks:
- [Portal] Create staging slot. Navigate to:
nordvex-webapp β Deployment β Deployment slots β Add slot- Name:
staging| Clone settings from:nordvex-webapp (production)
- Name:
- [Portal] Access slot URL:
https://nordvex-webapp-staging.azurewebsites.net - [Portal] Execute swap. Navigate to:
nordvex-webapp β Deployment β Deployment slots β Swap- Source:
staging| Target:production
- Source:
Validation Criteria:
- The Deployment slots blade should display 2 slots:
productionandstaging. - After swap, the production URL should correspond to content that was in the
stagingslot.
Domain 6 β Networkingβ
Step 57 β Create and configure virtual networks and subnetsβ
Context: A new production VNet should be created with planned address space and subnets segmented by function.
Tasks:
- [CLI] Create production VNet:
az network vnet create \
--name nordvex-vnet \
--resource-group nordvex-net-rg \
--location eastus \
--address-prefix 10.1.0.0/16
- [Portal] Create subnets. Navigate to:
nordvex-vnet β Subnets β + Subnet
| Subnet Name | Prefix | Purpose |
|---|---|---|
| nordvex-snet-vm | 10.1.1.0/24 | Production VMs |
| nordvex-snet-app | 10.1.2.0/24 | App Service Integration |
| nordvex-snet-data | 10.1.3.0/24 | Data resources and Key Vault |
| AzureBastionSubnet | 10.1.0.0/27 | Required for Azure Bastion (exact name) |
Validation Criteria:
az network vnet subnet list --vnet-name nordvex-vnet \
--resource-group nordvex-net-rg --output table
# Should return 4 subnets
Step 58 β Create and configure virtual network peeringβ
Context: For resources in nordvex-vnet and nordvex-vnet-temp to communicate, bidirectional peering is required.
Tasks:
- [Portal] Create peering. Navigate to:
nordvex-vnet β Peerings β + Add- Peering link name (local):
nordvex-peer-vnet-to-temp - Peering link name (remote):
nordvex-peer-temp-to-vnet - Virtual network:
nordvex-vnet-temp - Allow virtual network access: Enabled (both directions)
- Peering link name (local):
Validation Criteria:
az network vnet peering list --vnet-name nordvex-vnet --resource-group nordvex-net-rg --output table
az network vnet peering list --vnet-name nordvex-vnet-temp --resource-group nordvex-net-rg --output table
# Both should return peeringState = Connected
Step 59 β Configure public IPsβ
Context: The load balancer from Step 68 needs a static public IP for DNS configuration with fixed record.
Tasks:
- [CLI] Create public IP:
az network public-ip create \
--name nordvex-pip-lb \
--resource-group nordvex-net-rg \
--sku Standard \
--allocation-method Static \
--version IPv4 \
--dns-name nordvexlb \
--location eastus
Validation Criteria:
az network public-ip show --name nordvex-pip-lb --resource-group nordvex-net-rg \
--query "allocationMethod" --output tsv
# Should return: Static
Step 60 β Configure user-defined routes (UDR)β
Context: Outbound traffic from the VM subnet should pass through a simulated security appliance before exiting to the internet.
Tasks:
- [CLI] Create route table and route:
az network route-table create \
--name nordvex-rt \
--resource-group nordvex-net-rg \
--location eastus
az network route-table route create \
--route-table-name nordvex-rt \
--resource-group nordvex-net-rg \
--name nordvex-route-internet \
--address-prefix 0.0.0.0/0 \
--next-hop-type VirtualAppliance \
--next-hop-ip-address 10.1.1.254
- [Portal] Associate table with subnet. Navigate to:
nordvex-vnet β Subnets β nordvex-snet-vm β Route table β nordvex-rt β Save
Step 61 β Troubleshoot network connectivity issuesβ
Context: The team reported that nordvex-vm-dispatch cannot communicate with nordvex-vm-scada. Use Azure diagnostic tools to identify the cause.
Tasks:
- [Portal] Test IP flow. Navigate to:
Network Watcher β IP flow verify- VM:
nordvex-vm-dispatch| Direction: Inbound | Protocol: TCP | Port: 22 - Remote IP: Private IP of
nordvex-vm-scada
- VM:
- [Portal] Check next hop. Navigate to:
Network Watcher β Next hop - [Portal] Document the result and identify which NSG or route is causing the block.
Step 62 β Create and configure NSGs and application security groupsβ
Context: The NSG should limit access: only Bastion can connect via RDP/SSH and VMs can communicate with each other on port 80.
Tasks:
- [CLI] Create NSG and rules:
az network nsg create \
--name nordvex-nsg-vm \
--resource-group nordvex-net-rg
# Allow SSH from Bastion:
az network nsg rule create --nsg-name nordvex-nsg-vm --resource-group nordvex-net-rg \
--name AllowBastionSSH --priority 100 --direction Inbound \
--protocol Tcp --destination-port-ranges 22 \
--source-address-prefixes AzureBastionSubnet --access Allow
# Allow RDP from Bastion:
az network nsg rule create --nsg-name nordvex-nsg-vm --resource-group nordvex-net-rg \
--name AllowBastionRDP --priority 110 --direction Inbound \
--protocol Tcp --destination-port-ranges 3389 \
--source-address-prefixes AzureBastionSubnet --access Allow
# Allow HTTP between VMs:
az network nsg rule create --nsg-name nordvex-nsg-vm --resource-group nordvex-net-rg \
--name AllowVNetHTTP --priority 200 --direction Inbound \
--protocol Tcp --destination-port-ranges 80 \
--source-address-prefixes VirtualNetwork --access Allow
# Deny all else:
az network nsg rule create --nsg-name nordvex-nsg-vm --resource-group nordvex-net-rg \
--name DenyAllInbound --priority 4096 --direction Inbound \
--protocol "*" --destination-port-ranges "*" \
--source-address-prefixes "*" --access Deny
- [Portal] Associate NSG with subnet. Navigate to:
nordvex-nsg-vm β Settings β Subnets β Associate β nordvex-vnet β nordvex-snet-vm
Step 63 β Evaluate effective security rules in NSGsβ
Context: The auditor requested a visualization of effective rules applied to the SCADA VM's network interface.
Tasks:
- [Portal] View effective rules. Navigate to:
nordvex-vm-scada β Networking β Network interface β <nic-name> β Effective security rules - [CLI] Capture rules in JSON:
az network nic list-effective-nsg \
--name <nic-name> \
--resource-group nordvex-net-rg \
--output json
Step 64 β Implement Azure Bastionβ
Context: Administrative access to VMs should be exclusively via Azure Bastion, without exposing management ports to the internet.
Azure Bastion Basic generates ~USD 0.19/h. Delete the resource after use during the lab.
Tasks:
- [Portal] Create Bastion. Navigate to:
nordvex-vnet β Bastion β Create Azure Bastion- Name:
nordvex-bastion| SKU: Basic - Subnet:
AzureBastionSubnet(created in Step 57) - Public IP: Create new β
nordvex-pip-bastion
- Name:
- [Portal] After creation (~5β10 min), access
nordvex-vm-dispatchvia Bastion. Navigate to:nordvex-vm-dispatch β Connect β Bastion
Validation Criteria:
az network bastion show --name nordvex-bastion --resource-group nordvex-net-rg \
--query "provisioningState" --output tsv
# Should return: Succeeded
Step 65 β Configure service endpoints for Azure PaaSβ
Context: The nordvexstg account should be accessible only from the data subnet, without going through the public internet.
Tasks:
- [Portal] Add service endpoint. Navigate to:
nordvex-vnet β Subnets β nordvex-snet-data β Service endpoints β Add service endpoint- Service:
Microsoft.Storage
- Service:
- [Portal] Add subnet to storage firewall. Navigate to:
nordvexstg β Security + networking β Networking β Firewalls and virtual networks β Add existing virtual network- VNet:
nordvex-vnet| Subnet:nordvex-snet-data
- VNet:
Validation Criteria:
az network vnet subnet show --name nordvex-snet-data \
--vnet-name nordvex-vnet --resource-group nordvex-net-rg \
--query "serviceEndpoints[0].service" --output tsv
# Should return: Microsoft.Storage
Step 66 β Configure private endpoints for Azure PaaSβ
Context: Key Vault nordvex-kv should be accessible only via private endpoint within the VNet.
Tasks:
- [Portal] Create private endpoint. Navigate to:
nordvex-kv β Settings β Networking β Private endpoint connections β + Private endpoint- Name:
nordvex-pe-kv| Resource group:nordvex-net-rg - Target sub-resource:
vault - VNet:
nordvex-vnet| Subnet:nordvex-snet-data - Integrate with private DNS zone: Yes
- Name:
- [Portal] Disable public access. Navigate to:
nordvex-kv β Settings β Networking β Disable public access
Validation Criteria:
az network private-endpoint show --name nordvex-pe-kv \
--resource-group nordvex-net-rg \
--query "provisioningState" --output tsv
# Should return: Succeeded
Step 67 β Configure Azure DNSβ
Context: The name vm-scada.nordvex.internal should resolve to the corresponding VM's private IP within the VNet.
Tasks:
- [CLI] Create private DNS zone, link to VNet, and create A record:
az network private-dns zone create \
--name nordvex.internal \
--resource-group nordvex-net-rg
az network private-dns link vnet create \
--name nordvex-dns-link \
--resource-group nordvex-net-rg \
--zone-name nordvex.internal \
--virtual-network nordvex-vnet \
--registration-enabled true
az network private-dns record-set a add-record \
--zone-name nordvex.internal \
--resource-group nordvex-net-rg \
--record-set-name vm-scada \
--ipv4-address <private-IP-of-vm-scada>
Validation Criteria:
az network private-dns record-set a show \
--name vm-scada --zone-name nordvex.internal \
--resource-group nordvex-net-rg \
--query "aRecords[0].ipv4Address" --output tsv
# Should return nordvex-vm-scada's private IP
Step 68 β Configure public load balancerβ
Context: The load dispatch system requires request distribution between VMs with high availability.
Tasks:
- [Portal] Create Load Balancer. Navigate to:
Load balancers β Create- Name:
nordvex-lb| SKU: Standard | Type: Public - Frontend IP:
nordvex-pip-lb(created in Step 59)
- Name:
- [Portal] Configure backend pool. Navigate to:
nordvex-lb β Backend pools β + Add- Add NICs of
nordvex-vm-scadaandnordvex-vm-dispatch
- Add NICs of
- [Portal] Create load balancing rule. Navigate to:
nordvex-lb β Load balancing rules β + Add- Protocol: TCP | Port: 80 | Health probe: HTTP on port 80
Step 69 β Troubleshoot load balancing issuesβ
Context: The health probe is reporting failure on VMs. Identify and fix the cause.
Tasks:
- [Portal] Check health probe. Navigate to:
nordvex-lb β Monitoring β Metrics β Health Probe Status - [Portal] Run Connection troubleshoot. Navigate to:
Network Watcher β Connection troubleshoot - [CLI] Add permission rule for load balancer in NSG:
az network nsg rule create --nsg-name nordvex-nsg-vm --resource-group nordvex-net-rg \
--name AllowAzureLoadBalancer --priority 150 --direction Inbound \
--protocol Tcp --destination-port-ranges 80 \
--source-address-prefixes AzureLoadBalancer --access Allow
Domain 7 β Monitoringβ
Step 70 β Interpret metrics in Azure Monitorβ
Context: The operations team needs to monitor CPU and memory of the SCADA VM in real-time with a basic dashboard configured.
Tasks:
- [Portal] Access metrics. Navigate to:
Monitor β Metrics β Select a scope β nordvex-vm-scada- Add:
Percentage CPU,Available Memory Bytes,Disk Read Bytes
- Add:
- [Portal] Configure
Percentage CPU: Aggregation = Average | Time range = Last 24 hours - [Portal] Pin the chart. Click Pin to dashboard β Create new β Name: nordvex-dashboard
Step 71 β Configure log definitions in Azure Monitorβ
Context: All diagnostic logs from the VM, storage, and Key Vault should be sent to a Log Analytics workspace.
Tasks:
- [CLI] Create the workspace:
az monitor log-analytics workspace create \
--name nordvex-law \
--resource-group nordvex-rg \
--location eastus
# Capture the workspace ID:
az monitor log-analytics workspace show --name nordvex-law \
--resource-group nordvex-rg --query customerId --output tsv
- [Portal] Configure diagnostics on the VM. Navigate to:
nordvex-vm-scada β Monitoring β Diagnostic settings β Add diagnostic setting- Name:
nordvex-diag-vm| Destination:nordvex-law| Categories: All logs and metrics
- Name:
- [Portal] Repeat for
nordvexstg(nordvex-diag-storage) andnordvex-kv(nordvex-diag-kv).
Step 72 β Query and analyze logs in Azure Monitorβ
Context: The security team needs KQL queries for failed logins and recent activities.
Tasks:
- [Portal] Access logs. Navigate to:
nordvex-law β Logs - [Portal] Execute the failed login query:
SecurityEvent
| where TimeGenerated > ago(24h)
| where EventID == 4625
| summarize FailedLogins = count() by Account, Computer
| order by FailedLogins desc
- [Portal] Execute and save the activity query:
AzureActivity
| where TimeGenerated > ago(1h)
| summarize count() by ResourceGroup, OperationNameValue
| order by count_ desc
Save as: nordvex-query-activity
Step 73 β Configure alert rules, action groups, and processing rulesβ
Context: The NOC should be notified when the SCADA VM CPU exceeds 90% for more than 5 minutes.
Tasks:
- [Portal] Create the action group. Navigate to:
Monitor β Alerts β Action groups β + Create- Name:
nordvex-ag-noc| Short name:noc - Action type: Email/SMS | Email:
nordvex-ops-user@<yourdomain>
- Name:
- [Portal] Create the alert rule. Navigate to:
Monitor β Alerts β Alert rules β + Create- Scope:
nordvex-vm-scada - Condition: Percentage CPU > 90 (average, 5 min)
- Action group:
nordvex-ag-noc - Name:
nordvex-alert-cpu-scada| Severity: 2
- Scope:
- [Portal] Create an alert processing rule to suppress notifications on weekends.
Validation Criteria:
az monitor metrics alert show --name nordvex-alert-cpu-scada \
--resource-group nordvex-rg --query "enabled" --output tsv
# Should return: True
Step 74 β Configure and interpret monitoring with Azure Monitor Insightsβ
Context: VM Insights should be enabled for the SCADA VM and Storage Insights reviewed for the main account.
Tasks:
- [Portal] Enable VM Insights. Navigate to:
nordvex-vm-scada β Monitoring β Insights β Enable- Log Analytics workspace:
nordvex-law
- Log Analytics workspace:
- [Portal] After agent installation (up to 30 min), access the Performance tab of VM Insights.
- [Portal] Access Storage Insights. Navigate to:
nordvexstg β Monitoring β Insights
Step 75 β Use Azure Network Watcher and Connection Monitorβ
Context: The network team needs continuous monitoring of connectivity between VMs.
Tasks:
- [Portal] Confirm Network Watcher is enabled. Navigate to:
Network Watcher β Overview β East US β Enabled - [Portal] Create connection monitor. Navigate to:
Network Watcher β Connection monitor β Create- Name:
nordvex-cm-vm - Source:
nordvex-vm-dispatch - Destination: Private IP of
nordvex-vm-scada| Port: 22 - Test frequency: 30 seconds
- Name:
Domain 8 β Backup and Disaster Recoveryβ
Step 76 β Create a Recovery Services vaultβ
Context: The Recovery Services Vault is Nordvex's central backup and DR service.
This vault also enables the Azure Files backup configured in Step 30. After creating the vault here, you can return to Step 30 and enable integrated backup of the nordvex-share file share.
Tasks:
- [CLI] Create the vault:
az backup vault create \
--name nordvex-rsv \
--resource-group nordvex-rg \
--location eastus
- [Portal] Confirm redundancy. Navigate to:
nordvex-rsv β Settings β Properties β Backup configuration- Storage replication type: Geo-redundant
Validation Criteria:
az backup vault show --name nordvex-rsv --resource-group nordvex-rg \
--query "properties.provisioningState" --output tsv
# Should return: Succeeded
Step 77 β Create an Azure Backup vaultβ
Context: The Azure Backup Vault is the dedicated resource for modern workloads (managed disks, blobs, PostgreSQL).
Tasks:
- [Portal] Create the Backup Vault. Navigate to:
Backup center β Vaults β + Backup vault- Name:
nordvex-bv| Resource group:nordvex-rg| Region: East US - Backup storage redundancy: Geo-redundant
- Name:
Validation Criteria:
az dataprotection backup-vault list --resource-group nordvex-rg \
--query "[?name=='nordvex-bv'].provisioningState" --output tsv
# Should return: Succeeded
Step 78 β Create and configure a backup policyβ
Context: The policy should define daily VM backup with 30-day retention and weekly backup with 12-week retention.
Tasks:
- [Portal] Create the policy. Navigate to:
nordvex-rsv β Backup policies β + Add β Azure Virtual Machine- Policy name:
nordvex-backup-policy - Backup frequency: Daily | Time: 02:00 UTC
- Daily backup point retention: 30 days
- Weekly backup point: Sunday | Retention: 12 weeks
- Policy name:
Validation Criteria:
az backup policy show --name nordvex-backup-policy --vault-name nordvex-rsv \
--resource-group nordvex-rg \
--query "properties.schedulePolicy.schedulePolicyType" --output tsv
# Should return: SimpleSchedulePolicy
Step 79 β Perform backup and restore operations with Azure Backupβ
Context: The SCADA VM should be protected and an on-demand backup should be executed to validate the complete flow.
Tasks:
- [Portal] Enable protection. Navigate to:
nordvex-rsv β Backup β Azure Virtual Machine- Policy:
nordvex-backup-policy| Addnordvex-vm-scadaβ Enable Backup
- Policy:
- [Portal] Execute on-demand backup. Navigate to:
nordvex-rsv β Backup items β Azure Virtual Machine β nordvex-vm-scada β Backup now- Retain backup until: 30 days
- [Portal] Monitor progress. Navigate to:
nordvex-rsv β Monitoring + reports β Backup jobs
Validation Criteria:
- The Backup jobs blade should display the
nordvex-vm-scadajob with Completed status. - The Backup items blade should show the VM with at least 1 recovery point available.
Step 80 β Configure Azure Site Recoveryβ
Context: The SCADA VM should have continuous replication to the Brazil South region as part of the DR plan.
Site Recovery generates ~USD 0.16/VM/h while active. Disable replication after Step 81.
Tasks:
- [Portal] Configure replication. Navigate to:
nordvex-rsv β Site Recovery β Replicate- Source location: East US | VMs:
nordvex-vm-scada - Target location: Brazil South
- Target resource group:
nordvex-rg-dr(create automatically)
- Source location: East US | VMs:
- [Portal] Monitor progress. Navigate to:
nordvex-rsv β Site Recovery jobs
Validation Criteria:
The Replicated items blade should display nordvex-vm-scada with Protected status and synchronization at 100%.
Step 81 β Execute failover to secondary regionβ
Context: DR simulation. Execute a test failover to Brazil South without interrupting the production VM.
Tasks:
- [Portal] Execute test failover. Navigate to:
nordvex-rsv β Replicated items β nordvex-vm-scada β Test failover- Recovery point: Latest processed
- Azure virtual network: select or create a temporary VNet in Brazil South
- [Portal] Monitor. Navigate to:
nordvex-rsv β Site Recovery jobs - [Portal] Clean up test environment. Navigate to:
nordvex-rsv β Replicated items β nordvex-vm-scada β Cleanup test failover
Validation Criteria:
- The Test failover job should have Completed status.
- The Cleanup test failover operation should be completed without errors.
Step 82 β Configure and interpret backup reports and alertsβ
Context: The auditor needs a consolidated backup compliance report and an automatic alert for failures.
Tasks:
- [Portal] Configure reports. Navigate to:
nordvex-rsv β Monitoring + reports β Backup reports β Configure- Log Analytics workspace:
nordvex-law
- Log Analytics workspace:
- [Portal] Access the Summary dashboard and observe:
- Protected vs. unprotected instances
- Backup jobs in the last 24h
- Backup storage consumption
- [Portal] Create backup failure alert. Navigate to:
Monitor β Alerts β Alert rules β + Create- Signal type: Log (Log Analytics) | Workspace:
nordvex-law - KQL query:
- Signal type: Log (Log Analytics) | Workspace:
AddonAzureBackupJobs
| where JobStatus == "Failed"
| where TimeGenerated > ago(1h)
- Alert rule name:
nordvex-alert-backup-failure| Severity: 1 - Evaluation frequency: 1 hour | Action group:
nordvex-ag-noc
Validation Criteria:
az monitor scheduled-query list --resource-group nordvex-rg \
--query "[?name=='nordvex-alert-backup-failure'].enabled" --output tsv
# Should return: True
- The Backup reports blade should display at least 1 protected item (
nordvex-vm-scada). - The
nordvex-alert-backup-failurerule should appear inMonitor β Alert ruleswith Enabled status.
Final Environment Validationβ
Upon completing all 82 steps, the Nordvex environment should comprise the following resources:
| Category | Resources | Resource Group |
|---|---|---|
| Identity | 3 users, 2 groups, 1 guest, SSPR | Microsoft Entra ID |
| Governance | 2 policies, 1 lock, budget, management group | nordvex-rg |
| Storage | nordvexstg (ZRS + CMK), nordvexarchive (GRS) | nordvex-rg |
| Compute | nordvex-vm-scada, nordvex-vm-dispatch, nordvex-vmss | nordvex-net-rg |
| Containers | nordvexacr, nordvex-aci-billing, nordvex-ca-billing | nordvex-rg |
| App Service | nordvex-webapp (P1v3, 2 slots) | nordvex-rg |
| Network | nordvex-vnet, NSG, LB, Bastion, private DNS, UDR | nordvex-net-rg |
| Monitoring | nordvex-law, alerts, Connection Monitor | nordvex-rg |
| Backup and DR | nordvex-rsv, nordvex-bv, Site Recovery (Brazil South) | nordvex-rg |
Final validation query:
az resource list \
--query "[?starts_with(resourceGroup,'nordvex')]" \
--output table | wc -l
# The result should indicate at least 35 distinct resources
AZ-104 Lab β Nordvex Energia S.A. | Prefix: nordvex | 82 steps | 8 domains