Skip to main content

[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​

Install before starting

Validate all tools below before starting Step 1.

ToolMinimum VersionRequired in StepsVerification
Azure CLI2.50+Allaz --version
Bicep CLIAny33–36az bicep install && az bicep version
Docker Desktop24+45–46docker --version
AzCopyv10+25azcopy --version
Cost and time estimate
  • πŸ’° 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
ResourceEstimated costObservation
Azure Bastion (Basic)~USD 0.19/hTurn off after use
VM Standard_B4ms~USD 0.15/hDeallocate between sessions
VMSS (2x B2s)~USD 0.10/hReduce to 0 instances between sessions
App Service P1v3~USD 0.16/hScale down to F1 between sessions
Site Recovery~USD 0.16/VM/hDisable after Step 81

Index by Exam Domain​

DomainSteps
Domain 1 β€” Identity and Governance1–15
Domain 2 β€” Storage16–32
Domain 3 β€” Infrastructure as Code33–37
Domain 4 β€” Compute and Containers38–48
Domain 5 β€” App Service49–56
Domain 6 β€” Networking57–69
Domain 7 β€” Monitoring70–75
Domain 8 β€” Backup and DR76–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

FieldUser 1User 2User 3
Display namenordvex-ops-usernordvex-net-usernordvex-audit-user
User principal nameops@<yourdomain>net@<yourdomain>audit@<yourdomain>
PasswordManually setManually setManually set
Force change passwordNoNoNo

[Portal] Create two security groups. Navigate to: Microsoft Entra ID β†’ Groups β†’ New group

FieldGroup 1Group 2
Group namenordvex-ops-groupnordvex-net-group
Group typeSecuritySecurity
Membership typeAssignedAssigned
Membersnordvex-ops-usernordvex-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
tip

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

UserJob titleDepartmentBusiness phone
nordvex-ops-userCloud OperatorIT+55-31-0000-0001
nordvex-net-userNetwork EngineerNetworks+55-31-0000-0002
nordvex-audit-userIT AuditorAuditing+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:

  1. [Portal] Check available licenses. Navigate to: Microsoft Entra ID β†’ Billing β†’ Licenses β†’ All products
  2. [Portal] Assign license to group. Navigate to: Microsoft Entra ID β†’ Groups β†’ nordvex-ops-group β†’ Licenses β†’ Assignments
  3. [Portal] Check inheritance in user. Navigate to: Microsoft Entra ID β†’ Users β†’ nordvex-ops-user β†’ Licenses

Validation Criteria:

tip
  • In the nordvex-ops-user β†’ Licenses profile, 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:

  1. [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
  2. [Portal] Confirm that User type = Guest. Navigate to: Microsoft Entra ID β†’ Users β†’ nordvex-ext-voltec β†’ Properties
  3. [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:

  1. [Portal] Enable SSPR. Navigate to: Microsoft Entra ID β†’ Password reset β†’ Properties
    • Self service password reset enabled: Selected
    • Add nordvex-ops-group as scope
  2. [Portal] Configure methods. Navigate to: Microsoft Entra ID β†’ Password reset β†’ Authentication methods
    • Number of methods required: 1
    • Enable: Email and Mobile phone
  3. [Portal] Configure registration. Navigate to: Microsoft Entra ID β†’ Password reset β†’ Registration
    • Require users to register when signing in: Yes
    • Reconfirmation days: 180

Validation Criteria:

tip
  • Password reset β†’ Properties: scope should display Selected with nordvex-ops-group listed.
  • 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:

  1. [Portal] Create the main resource group. Navigate to: Resource groups β†’ Create
    • Name: nordvex-rg | Region: East US
  2. [Portal] Assign Contributor to group. Navigate to: nordvex-rg β†’ Access control (IAM) β†’ Add role assignment
    • Role: Contributor | Assignee: nordvex-ops-group
  3. [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
  1. [Portal] Assign Billing Reader to auditor. Navigate to: Subscriptions β†’ <subscription> β†’ Access control (IAM) β†’ Add role assignment
    • Role: Billing Reader | Assignee: nordvex-audit-user

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:

  1. [CLI] Create the development resource group:
az group create --name nordvex-dev-rg --location eastus
  1. [Portal] Assign Reader to nordvex-ops-user in nordvex-dev-rg. Navigate to: nordvex-dev-rg β†’ Access control (IAM) β†’ Add role assignment
  2. [CLI] List all assignments across all scopes:
az role assignment list --assignee <objectId-ops-user> --all --output table

Validation Criteria:

tip
  • The --all command 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:

  1. [Portal] Check effective access. Navigate to: nordvex-rg β†’ Access control (IAM) β†’ Check access β†’ Search nordvex-ops-user
  2. [Portal] View assignments. Navigate to: nordvex-rg β†’ Access control (IAM) β†’ Role assignments β†’ Type: All
  3. [CLI] Capture all assignments including inherited:
az role assignment list --resource-group nordvex-rg --include-inherited --output table

Validation Criteria:

tip
  • Check access for nordvex-ops-user should 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:

  1. [Portal] Assign location policy. Navigate to: Policy β†’ Assignments β†’ Assign policy
    • Scope: nordvex-rg
    • Policy definition: "Allowed locations"
    • Allowed locations: eastus, brazilsouth
  2. [Portal] Assign tag policy. Navigate to: Policy β†’ Assignments β†’ Assign policy
    • Policy definition: "Require a tag and its value"
    • Tag name: CostCenter | Tag value: NordvexProd
  3. [CLI] Confirm assignments:
az policy assignment list --resource-group nordvex-rg --output table
# Should return at least 2 entries
  1. [Portal] Try to create a Storage Account in West US within nordvex-rg and 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:

  1. [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
  2. [CLI] Confirm:
az lock list --resource-group nordvex-rg --output table
# lockType = CanNotDelete, name = nordvex-lock-delete
  1. [Portal] Logged in as nordvex-ops-user (Contributor), try to delete nordvex-rg and observe the lock.

Step 11 β€” Apply and manage tags on resources​

Context: The CFO requires granular cost visibility by cost center and environment.

Tasks:

  1. [CLI] Apply the three tags to the resource group:
az group update --name nordvex-rg \
--tags CostCenter=NordvexProd Environment=Production ManagedBy=CloudOps
  1. [Portal] Confirm tags. Navigate to: nordvex-rg β†’ Tags
  2. [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:

  1. [CLI] Create the network resource group:
az group create --name nordvex-net-rg --location eastus \
--tags CostCenter=NordvexProd Environment=Production ManagedBy=CloudOps
  1. [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
  2. [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:

  1. [CLI] List subscriptions:
az account list --output table
  1. [Portal] Rename the subscription. Navigate to: Subscriptions β†’ <subscription> β†’ Overview β†’ Rename
    • New name: Nordvex-Production
  2. [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:

  1. [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
  2. [Portal] Review recommendations. Navigate to: Advisor β†’ Cost
  3. [Portal] Add 100% alert to the same budget.

Validation Criteria:

tip
  • The budget nordvex-budget-q1 should 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:

  1. [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
  2. [Portal] Move the production subscription to the group. Navigate to: nordvex-mg β†’ Add subscription
  3. [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:

  1. [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
  1. [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-temp as allowed network
  2. [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:

  1. [Portal] Create the log container. Navigate to: nordvexstg β†’ Data storage β†’ Containers β†’ + Container
    • Name: nordvex-logs | Public access level: Private
  2. [Portal] Generate the SAS token. Navigate to: nordvexstg β†’ Security + networking β†’ Shared access signature
ParameterValue
Allowed servicesBlob only
Allowed resource typesObject only
Allowed permissionsRead, Write
Expiry24 hours from now
Allowed protocolsHTTPS only
  1. [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:

  1. [Portal] Create the policy. Navigate to: nordvexstg β†’ Containers β†’ nordvex-logs β†’ Access policy β†’ Add policy
    • Identifier: nordvex-log-policy | Permissions: Read, Write | Expiry: 7 days
  2. [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:

tip
  • The policy nordvex-log-policy should appear listed in Access policy of the nordvex-logs container.
  • The generated SAS token should contain the parameter si=nordvex-log-policy in 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:

  1. [Portal] View the keys. Navigate to: nordvexstg β†’ Security + networking β†’ Access keys
  2. [Portal] Regenerate key1. Click Rotate key next to key1. Capture the new value.
  3. [CLI] Confirm:
az storage account keys list \
--account-name nordvexstg \
--resource-group nordvex-rg \
--output table

Validation Criteria:

tip
  • The command should return two objects: key1 and key2.
  • The operation should appear in the Activity log of nordvex-rg as 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:

  1. [Portal] Create the file share. Navigate to: nordvexstg β†’ Data storage β†’ File shares β†’ + File share
    • Name: nordvex-share | Quota: 50 GiB | Tier: Transaction optimized
  2. [Portal] Enable Entra ID authentication. Navigate to: nordvexstg β†’ Data management β†’ Configuration β†’ Identity-based access β†’ Microsoft Entra Kerberos
  3. [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

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:

  1. [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
  1. [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:

  1. [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:

  1. [Portal] Enable versioning on both accounts (prerequisite for replication).
    • nordvexstg β†’ Data protection β†’ Enable versioning for blobs
    • Repeat for nordvexarchive
  2. [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)

Validation Criteria:

tip
  • Object replication in nordvexstg should display at least 1 policy with status Enabled.
  • The container nordvex-logs-replica should exist in nordvexarchive.

Step 24 β€” Configure storage account encryption (CMK)​

Context: The legal department requires customer-managed keys (CMK) for regulatory compliance.

Tasks:

  1. [Portal] Create the Key Vault. Navigate to: Key vaults β†’ Create
    • Name: nordvex-kv | Resource group: nordvex-rg | Region: East US | Soft delete: Enabled
  2. [Portal] Create the key. Navigate to: nordvex-kv β†’ Objects β†’ Keys β†’ Generate/Import
    • Name: nordvex-storage-key | Key type: RSA | Key size: 2048
  3. [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.

Prerequisite

AzCopy v10+ installed locally. Check with: azcopy --version

Tasks:

  1. [CLI] Upload via AzCopy:
azcopy copy "./logs-locais/*" \
"https://nordvexstg.blob.core.windows.net/nordvex-logs?<SAS-token>" \
--recursive
  1. [Portal] Confirm the files. Navigate to: nordvexstg β†’ Storage browser β†’ Blob containers β†’ nordvex-logs
  2. [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:

  1. [Portal] Create a directory. Navigate to: nordvexstg β†’ File shares β†’ nordvex-share β†’ + Add directory
    • Name: subestacoes
  2. [Portal] Upload a test file to the subestacoes directory.
  3. [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:

  1. [Portal] Create the backup container. Navigate to: nordvexstg β†’ Data storage β†’ Containers β†’ + Container
    • Name: nordvex-backups | Public access level: Private
  2. [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:

  1. [Portal] Change a blob tier manually. Navigate to: nordvexstg β†’ Storage browser β†’ Blob containers β†’ nordvex-backups β†’ <blob> β†’ Change tier β†’ Cool
  2. [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:

  1. [Portal] Enable soft delete for blobs. Navigate to: nordvexstg β†’ Data protection β†’ Enable soft delete for blobs
    • Retention period: 14 days
  2. [Portal] Enable soft delete for containers. Navigate to: nordvexstg β†’ Data protection β†’ Enable soft delete for containers
    • Retention period: 7 days
  3. [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.

Note about integrated backup

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:

  1. [Portal] Enable soft delete for file shares. Navigate to: nordvexstg β†’ Data protection β†’ Enable soft delete for file shares
    • Retention period: 14 days
  2. [Portal] Create a manual snapshot. Navigate to: nordvexstg β†’ File shares β†’ nordvex-share β†’ Operations β†’ Snapshots β†’ Add snapshot
  3. [Portal] Confirm the snapshot. Navigate to: nordvex-share β†’ Operations β†’ Snapshots

Validation Criteria:

tip
  • 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:

  1. [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
ConditionAction
Blobs older than 30 daysMove to Cool storage
Blobs older than 90 daysMove to Archive storage
Blobs older than 365 daysDelete the blob
  1. [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:

  1. [Portal] Confirm that versioning is enabled. Navigate to: nordvexstg β†’ Data protection β†’ Enable versioning for blobs
  2. [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
  1. [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)​

Prerequisite

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:

  1. [Portal] Export the ARM template from a previous deployment. Navigate to: nordvex-rg β†’ Deployments β†’ <deployment> β†’ Template β†’ Download
  2. [IaC] Analyze the exported template and identify:
    • How many resources are declared in the resources section
    • Which parameters have defaultValue
    • Which explicit dependencies (dependsOn) are present
  3. [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:

  1. [IaC] Add the tags block with CostCenter: NordvexProd to each resource in the resources section.
  2. [IaC] Add an environment parameter of type string with defaultValue: "Production" and use it as the value for the Environment tag.
  3. [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:

  1. [IaC] Add a new storage resource to the .bicep file:
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
  1. [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:

  1. [CLI] Execute the deployment:
az deployment group create \
--resource-group nordvex-rg \
--template-file template.bicep \
--parameters environment=Production \
--name nordvex-bicep-deploy
  1. [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:

  1. [Portal] Export the template for the entire group. Navigate to: nordvex-rg β†’ Automation β†’ Export template β†’ Download
  2. [CLI] Export via CLI:
az group export --name nordvex-rg > nordvex-rg-export.json

Validation Criteria:

tip
  • The exported file must contain at least 3 distinct resources in the resources section.
  • Valid JSON verification: cat nordvex-rg-export.json | python3 -m json.tool

Domain 4 β€” Compute and Containers​

Prerequisite for Steps 45–46

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:

  1. [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
  1. [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:

  1. [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
  1. [CLI] Stop and deallocate the VM:
az vm deallocate --name nordvex-vm-scada --resource-group nordvex-rg
  1. [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:

  1. [Portal] Move the VM. Navigate to: nordvex-vm-scada β†’ Overview β†’ Move β†’ Move to another resource group
    • Destination resource group: nordvex-net-rg

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:

  1. [CLI] List available sizes:
az vm list-vm-resize-options --name nordvex-vm-scada --resource-group nordvex-net-rg --output table
  1. [Portal] Resize. Navigate to: nordvex-vm-scada β†’ Availability + scale β†’ Size β†’ Standard_B4ms β†’ Resize
info

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:

  1. [Portal] Add data disk. Navigate to: nordvex-vm-scada β†’ Settings β†’ Disks β†’ + Create and attach a new disk
ParameterValue
Disk namenordvex-disk-scada
Size128 GiB
Disk typePremium SSD
Host cachingRead-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:

  1. [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
  1. [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:

  1. [Portal] Create the VMSS. Navigate to: Virtual machine scale sets β†’ Create
ParameterValue
Namenordvex-vmss
Resource groupnordvex-rg
RegionEast US
ImageUbuntu Server 22.04 LTS
SizeStandard_B2s
Initial count2
Orchestration modeUniform
  1. [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.

warning

Docker Desktop must be installed and running.

Tasks:

  1. [CLI] Create the Container Registry:
az acr create \
--name nordvexacr \
--resource-group nordvex-rg \
--sku Basic \
--location eastus
  1. [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:

  1. [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:

  1. [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:

  1. [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
  2. [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.

Cost

App Service P1v3 generates ~USD 0.16/h. Scale down to F1 between sessions if needed.

Tasks:

  1. [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:

  1. [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:

  1. [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
  1. [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:

  1. [Portal] Force HTTPS. Navigate to: nordvex-webapp β†’ Settings β†’ Configuration β†’ General settings
    • HTTPS Only: On
  2. [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:

  1. [Portal] Access the domains blade. Navigate to: nordvex-webapp β†’ Settings β†’ Custom domains β†’ Add custom domain
  2. [Portal] Observe and document the required DNS records:
    • Verification TXT record
    • App Service IP address for A record
  3. [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:

  1. [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
  2. [Portal] Execute immediate backup: Backups β†’ Backup now

Validation Criteria:

tip
  • The Backups blade should display at least 1 entry with Succeeded status.
  • The nordvex-backups container 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:

  1. [Portal] Add subnet to VNet. Navigate to: nordvex-vnet-temp β†’ Subnets β†’ + Subnet
    • Name: nordvex-snet-app | Address range: 10.0.2.0/24
  2. [Portal] Configure VNet Integration. Navigate to: nordvex-webapp β†’ Settings β†’ Networking β†’ VNet integration β†’ Add VNet integration
    • Virtual network: nordvex-vnet-temp | Subnet: nordvex-snet-app
  3. [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:

  1. [Portal] Create staging slot. Navigate to: nordvex-webapp β†’ Deployment β†’ Deployment slots β†’ Add slot
    • Name: staging | Clone settings from: nordvex-webapp (production)
  2. [Portal] Access slot URL: https://nordvex-webapp-staging.azurewebsites.net
  3. [Portal] Execute swap. Navigate to: nordvex-webapp β†’ Deployment β†’ Deployment slots β†’ Swap
    • Source: staging | Target: production

Validation Criteria:

tip
  • The Deployment slots blade should display 2 slots: production and staging.
  • After swap, the production URL should correspond to content that was in the staging slot.

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:

  1. [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
  1. [Portal] Create subnets. Navigate to: nordvex-vnet β†’ Subnets β†’ + Subnet
Subnet NamePrefixPurpose
nordvex-snet-vm10.1.1.0/24Production VMs
nordvex-snet-app10.1.2.0/24App Service Integration
nordvex-snet-data10.1.3.0/24Data resources and Key Vault
AzureBastionSubnet10.1.0.0/27Required 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:

  1. [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)

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:

  1. [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:

  1. [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
  1. [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:

  1. [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
  2. [Portal] Check next hop. Navigate to: Network Watcher β†’ Next hop
  3. [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:

  1. [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
  1. [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:

  1. [Portal] View effective rules. Navigate to: nordvex-vm-scada β†’ Networking β†’ Network interface β†’ <nic-name> β†’ Effective security rules
  2. [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.

Cost

Azure Bastion Basic generates ~USD 0.19/h. Delete the resource after use during the lab.

Tasks:

  1. [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
  2. [Portal] After creation (~5–10 min), access nordvex-vm-dispatch via 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:

  1. [Portal] Add service endpoint. Navigate to: nordvex-vnet β†’ Subnets β†’ nordvex-snet-data β†’ Service endpoints β†’ Add service endpoint
    • Service: Microsoft.Storage
  2. [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

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:

  1. [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
  2. [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:

  1. [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:

  1. [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)
  2. [Portal] Configure backend pool. Navigate to: nordvex-lb β†’ Backend pools β†’ + Add
    • Add NICs of nordvex-vm-scada and nordvex-vm-dispatch
  3. [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:

  1. [Portal] Check health probe. Navigate to: nordvex-lb β†’ Monitoring β†’ Metrics β†’ Health Probe Status
  2. [Portal] Run Connection troubleshoot. Navigate to: Network Watcher β†’ Connection troubleshoot
  3. [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:

  1. [Portal] Access metrics. Navigate to: Monitor β†’ Metrics β†’ Select a scope β†’ nordvex-vm-scada
    • Add: Percentage CPU, Available Memory Bytes, Disk Read Bytes
  2. [Portal] Configure Percentage CPU: Aggregation = Average | Time range = Last 24 hours
  3. [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:

  1. [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
  1. [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
  2. [Portal] Repeat for nordvexstg (nordvex-diag-storage) and nordvex-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:

  1. [Portal] Access logs. Navigate to: nordvex-law β†’ Logs
  2. [Portal] Execute the failed login query:
SecurityEvent
| where TimeGenerated > ago(24h)
| where EventID == 4625
| summarize FailedLogins = count() by Account, Computer
| order by FailedLogins desc
  1. [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:

  1. [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>
  2. [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
  3. [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:

  1. [Portal] Enable VM Insights. Navigate to: nordvex-vm-scada β†’ Monitoring β†’ Insights β†’ Enable
    • Log Analytics workspace: nordvex-law
  2. [Portal] After agent installation (up to 30 min), access the Performance tab of VM Insights.
  3. [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:

  1. [Portal] Confirm Network Watcher is enabled. Navigate to: Network Watcher β†’ Overview β†’ East US β†’ Enabled
  2. [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

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.

info

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:

  1. [CLI] Create the vault:
az backup vault create \
--name nordvex-rsv \
--resource-group nordvex-rg \
--location eastus
  1. [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:

  1. [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

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:

  1. [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

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:

  1. [Portal] Enable protection. Navigate to: nordvex-rsv β†’ Backup β†’ Azure Virtual Machine
    • Policy: nordvex-backup-policy | Add nordvex-vm-scada β†’ Enable Backup
  2. [Portal] Execute on-demand backup. Navigate to: nordvex-rsv β†’ Backup items β†’ Azure Virtual Machine β†’ nordvex-vm-scada β†’ Backup now
    • Retain backup until: 30 days
  3. [Portal] Monitor progress. Navigate to: nordvex-rsv β†’ Monitoring + reports β†’ Backup jobs

Validation Criteria:

tip
  • The Backup jobs blade should display the nordvex-vm-scada job 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.

Cost

Site Recovery generates ~USD 0.16/VM/h while active. Disable replication after Step 81.

Tasks:

  1. [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)
  2. [Portal] Monitor progress. Navigate to: nordvex-rsv β†’ Site Recovery jobs

Validation Criteria:

tip

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:

  1. [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
  2. [Portal] Monitor. Navigate to: nordvex-rsv β†’ Site Recovery jobs
  3. [Portal] Clean up test environment. Navigate to: nordvex-rsv β†’ Replicated items β†’ nordvex-vm-scada β†’ Cleanup test failover

Validation Criteria:

tip
  • 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:

  1. [Portal] Configure reports. Navigate to: nordvex-rsv β†’ Monitoring + reports β†’ Backup reports β†’ Configure
    • Log Analytics workspace: nordvex-law
  2. [Portal] Access the Summary dashboard and observe:
    • Protected vs. unprotected instances
    • Backup jobs in the last 24h
    • Backup storage consumption
  3. [Portal] Create backup failure alert. Navigate to: Monitor β†’ Alerts β†’ Alert rules β†’ + Create
    • Signal type: Log (Log Analytics) | Workspace: nordvex-law
    • KQL query:
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
tip
  • The Backup reports blade should display at least 1 protected item (nordvex-vm-scada).
  • The nordvex-alert-backup-failure rule should appear in Monitor β†’ Alert rules with Enabled status.

Final Environment Validation​

Upon completing all 82 steps, the Nordvex environment should comprise the following resources:

CategoryResourcesResource Group
Identity3 users, 2 groups, 1 guest, SSPRMicrosoft Entra ID
Governance2 policies, 1 lock, budget, management groupnordvex-rg
Storagenordvexstg (ZRS + CMK), nordvexarchive (GRS)nordvex-rg
Computenordvex-vm-scada, nordvex-vm-dispatch, nordvex-vmssnordvex-net-rg
Containersnordvexacr, nordvex-aci-billing, nordvex-ca-billingnordvex-rg
App Servicenordvex-webapp (P1v3, 2 slots)nordvex-rg
Networknordvex-vnet, NSG, LB, Bastion, private DNS, UDRnordvex-net-rg
Monitoringnordvex-law, alerts, Connection Monitornordvex-rg
Backup and DRnordvex-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