[AZ-104] Grand Labs - NovaCarga Logistica S.A
Cumulative Real Deployment Environmentβ
Central Narrativeβ
Company: NovaCarga LogΓstica S.A. | Industry: Logistics and fractional cargo transportation | Headquarters: SΓ£o Paulo, Brazil
NovaCarga is a medium-sized company with 1,200 employees distributed between its headquarters in SΓ£o Paulo and branches in Recife, Porto Alegre, and Manaus. Following a security audit and an unauthorized data access incident involving client data, the board approved the complete migration of IT infrastructure to Azure.
The project was named Project Anchor and you are the cloud engineer responsible for implementation. The environment will be built from scratch, following requirements gathered by the architecture team: centralized identity in Microsoft Entra ID, network segmentation by workload function, secure storage for tax documents and tracking logs, VMs for legacy WMS and TMS systems, containers for microservices of the new tracking platform, and monitoring in compliance with LGPD policies.
Each step of this lab corresponds to a real delivery of Project Anchor. The prefix for all resources is ncarga. 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 |
|---|---|---|---|
| PowerShell | 7.2+ | All | $PSVersionTable.PSVersion |
| Az PowerShell module | 10.0+ | All | Get-Module Az -ListAvailable |
| Microsoft.Graph module | 2.0+ | 1β5 | Get-Module Microsoft.Graph -ListAvailable |
| Bicep CLI | Any | 33β36 | bicep --version |
| Docker Desktop | 24+ | 44β46 | docker --version |
| Azure CLI | 2.50+ | 46β47 | az --version |
| AzCopy | v10+ | 25 | azcopy --version |
- π° Estimated cost for complete execution: USD 20β45
- β±οΈ Estimated total time: 14β18 hours distributed across multiple sessions
- π Shut down and deallocate VMs, VMSS, and Bastion when ending each session
- π Primary region: East US | DR region: Brazil South
| Resource | Estimated cost | Note |
|---|---|---|
| Azure Bastion (Standard) | ~USD 0.19/h | Shut down after use |
| VM Standard_D4s_v3 | ~USD 0.19/h | Deallocate between sessions |
| VMSS (2x D2s_v3) | ~USD 0.19/h | Scale down 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 78 |
| Load Balancer Standard | ~USD 0.008/h | Low cost, can maintain |
Naming Conventionβ
| Resource Type | Example |
|---|---|
| Resource group | ncarga-rg-storage |
| Virtual network | ncarga-vnet-compute |
| VM | ncarga-vm-wms01 |
| Storage account | ncargatms001 (no hyphens, max 24 chars) |
| NSG | ncarga-nsg-compute |
| Key Vault | ncarga-kv-001 |
Index by Exam Domainβ
| Domain | Steps |
|---|---|
| Domain 1 β Identity and Governance | 1β15 |
| Domain 2 β Storage | 16β32 |
| Domain 3 β Infrastructure as Code | 33β36 |
| Domain 4 β Compute and Containers | 37β47 |
| Domain 5 β App Service | 48β53 |
| Domain 6 β Networking | 54β66 |
| Domain 7 β Monitoring | 67β72 |
| Domain 8 β Backup and DR | 73β79 |
Domain 1 β Identity and Governanceβ
Step 1 β Create users and groups in Microsoft Entra IDβ
Context: Project Anchor begins with identity. Before any Azure resource is provisioned, NovaCarga's IT team needs to exist in Microsoft Entra ID. The audit identified that users were sharing credentials and there were no security groups to control access by role.
Tasks:
[PowerShell] Create three member users in the tenant with the parameters below using New-MgUser. Set UsageLocation to BR, AccountEnabled to $true and generate temporary password with ForceChangePasswordNextSignIn enabled. Capture the Id of each user after creation.
| DisplayName | UserPrincipalName | JobTitle | Department |
|---|---|---|---|
| Ana Ferreira | ana.ferreira@<tenant>.onmicrosoft.com | Cloud Engineer | TI |
| Bruno Oliveira | bruno.oliveira@<tenant>.onmicrosoft.com | WMS Admin | Operacoes |
| Carla Mendes | carla.mendes@<tenant>.onmicrosoft.com | Finance Analyst | Financeiro |
[PowerShell] Create two security groups with SecurityEnabled = $true and MailEnabled = $false using New-MgGroup. Add the indicated members with New-MgGroupMember.
| DisplayName | MailNickname | Initial members |
|---|---|---|
| ncarga-ti | ncarga-ti | ana.ferreira |
| ncarga-ops | ncarga-ops | bruno.oliveira |
[Portal] Confirm the users and groups by navigating to: Microsoft Entra ID β Users and Microsoft Entra ID β Groups. Verify that each user's Usage location field is set to Brazil.
Validation Criteria:
# Should return UsageLocation = BR:
Get-MgUser -Filter "startsWith(UserPrincipalName,'ana.ferreira')" |
Select-Object DisplayName, UserPrincipalName, UsageLocation
# Should return ana.ferreira's Id:
Get-MgGroupMember -GroupId (Get-MgGroup -Filter "displayName eq 'ncarga-ti'").Id |
Select-Object Id
Step 2 β Manage user and group propertiesβ
Context: The HR team requested adjustments to profile attributes so that license and audit reports are correct. Additionally, the ncarga-ops group needs to be converted to dynamic membership, as the volume of seasonal hires makes manual management unfeasible.
Tasks:
[PowerShell] Update the three users with Update-AzureADUser. Add the CompanyName attribute with value NovaCarga Logistica SA and OfficeLocation as Sao Paulo HQ for all.
[PowerShell] Convert the ncarga-ops group to dynamic membership using Update-MgGroup. Set the dynamic rule to include users whose department equals Operacoes and MembershipType as DynamicMembership.
Dynamic groups require Microsoft Entra ID P1 or higher license in the tenant.
[Portal] Confirm the dynamic rule at: Microsoft Entra ID β Groups β ncarga-ops β Dynamic membership rules. Wait for processing and verify that bruno.oliveira appears as a dynamic member.
Validation Criteria:
# Should return NovaCarga Logistica SA:
Get-MgUser -Filter "displayName eq 'Ana Ferreira'" -Property CompanyName |
Select-Object CompanyName
# Should return Dynamic:
Get-MgGroup -Filter "displayName eq 'ncarga-ops'" |
Select-Object MembershipType
Step 3 β Manage licenses in Microsoft Entra IDβ
Context: NovaCarga purchased Microsoft 365 Business Premium licenses for Project Anchor users. The legal team requires that only active users with defined UsageLocation can receive licenses β a requirement derived from LGPD compliance policy.
Tasks:
[PowerShell] List available license SKUs in the tenant using Get-MgSubscribedSku. Capture the SkuId corresponding to the available plan with remaining units.
[PowerShell] Assign the captured license to the three users using Set-MgUserLicense. The AddLicenses parameter should contain the object with SkuId. Do not disable individual service plans.
[Portal] Confirm the assignment by navigating to: Microsoft Entra ID β Users β [user] β Licenses. The license should appear as Assigned for each of the three users.
Validation Criteria:
# Should return filled SkuPartNumber and status Enabled:
Get-MgUserLicenseDetail -UserId (Get-MgUser -Filter "displayName eq 'Ana Ferreira'").Id |
Select-Object SkuPartNumber, ServicePlans
Step 4 β Manage external usersβ
Context: NovaCarga hired an external consultancy, LogiPartners, to assist with tracking system configuration during the first three months of Project Anchor. The external user needs controlled access to the tenant, without being promoted to permanent member.
Tasks:
[PowerShell] Invite external user consultor@logipartners.example.com using New-MgInvitation with the parameters:
| Parameter | Value |
|---|---|
| InvitedUserDisplayName | Consultor LogiPartners |
| InviteRedirectUrl | https://portal.azure.com |
| SendInvitationMessage | $true |
Capture the invited user's Id from the command output.
[Portal] Confirm the guest user at: Microsoft Entra ID β Users. Filter by User type = Guest and verify the status PendingAcceptance or Accepted.
[Portal] Add the invited user to the ncarga-ti group by navigating to: Microsoft Entra ID β Groups β ncarga-ti β Members β Add members.
Validation Criteria:
# Should return UserType = Guest:
Get-MgUser -Filter "userType eq 'Guest'" |
Where-Object { $_.Mail -like "*logipartners*" } |
Select-Object DisplayName, UserType, Mail
# Should include Consultor LogiPartners with UserType = Guest:
Get-MgGroupMember -GroupId (Get-MgGroup -Filter "displayName eq 'ncarga-ti'").Id |
ForEach-Object { Get-MgUser -UserId $_.Id } |
Select-Object DisplayName, UserType
Step 5 β Configure Self-Service Password Reset (SSPR)β
Context: The helpdesk registers an average of 40 monthly calls related to password reset. The IT manager approved SSPR deployment for the ncarga-ti group, reducing operational load before the remaining users are migrated.
Tasks:
[Portal] Enable SSPR for Selected groups and select ncarga-ti. Navigate to: Microsoft Entra ID β Protection β Password reset β Properties.
[Portal] Configure authentication methods at: Microsoft Entra ID β Protection β Password reset β Authentication methods
| Parameter | Value |
|---|---|
| Number of methods required to reset | 1 |
| Methods available | Mobile app code, Email |
[Portal] Enable mandatory registration and set reconfirmation interval at: Microsoft Entra ID β Protection β Password reset β Registration
| Parameter | Value |
|---|---|
| Require users to register when signing in | Yes |
| Number of days before users are asked to re-confirm | 180 |
Validation Criteria:
Password reset β Properties: Self service password reset enabled field = Selected,ncarga-tigroup listed.Password reset β Authentication methods: Number of methods required = 1, enabled methods include Mobile app code and Email.
Step 6 β Manage Azure built-in roles (RBAC)β
Context: With identity structured, the architecture team defined the Azure access model. Ana Ferreira needs administrative access to the environment, Bruno Oliveira needs read access to operations resources, and the external consultant should have access only to monitor the environment.
Tasks:
[PowerShell] Assign the Contributor role to ana.ferreira at the current subscription scope using New-AzRoleAssignment with parameters SignInName, RoleDefinitionName and Scope. Capture the generated RoleAssignmentId.
[PowerShell] Assign the Reader role to the ncarga-ops group at subscription scope. Use the group's ObjectId obtained in Step 1.
[PowerShell] Assign the Monitoring Reader role to guest user consultor@logipartners.example.com at subscription scope.
Validation Criteria:
# Should return 3 lines with Contributor, Reader and Monitoring Reader roles:
Get-AzRoleAssignment -Scope "/subscriptions/<subscription-id>" |
Where-Object { $_.DisplayName -in @('Ana Ferreira','ncarga-ops','Consultor LogiPartners') } |
Select-Object DisplayName, RoleDefinitionName, Scope
Step 7 β Assign roles at different scopesβ
Context: Carla Mendes, from the finance team, needs administrative access only to the finance resource group, without access to the rest of the environment. This step demonstrates the principle of least privilege applied to granular scopes.
Tasks:
[PowerShell] Create the resource group ncarga-rg-financeiro in the brazilsouth region using New-AzResourceGroup.
[PowerShell] Assign the Contributor role to carla.mendes at scope /subscriptions/<id>/resourceGroups/ncarga-rg-financeiro using New-AzRoleAssignment.
[PowerShell] Confirm that Carla does not have assignment at subscription scope. Use Get-AzRoleAssignment -SignInName carla.mendes@... and check the Scope field.
Validation Criteria:
# Should return Contributor with Scope = .../resourceGroups/ncarga-rg-financeiro
# Should not show Scope = /subscriptions/<id> for Carla:
Get-AzRoleAssignment -SignInName "carla.mendes@<tenant>.onmicrosoft.com" |
Select-Object RoleDefinitionName, Scope
Step 8 β Interpret access assignmentsβ
Context: Before proceeding with creating the remaining resource groups, the security team requested a review of effective access assignments for each user, documenting inherited and direct access for each identity.
Tasks:
[PowerShell] List all role assignments for the current subscription, filtering by the three member users and the ncarga-ops group, using Get-AzRoleAssignment -IncludeClassicAdministrators $false.
[Portal] Check effective access for ana.ferreira and carla.mendes at: Subscription β Access control (IAM) β Check access. Include roles inherited from groups.
[PowerShell] Generate a consolidated report in table format with DisplayName, RoleDefinitionName, Scope and ObjectType for all Project Anchor principals. Export to ~/ncarga/rbac-report.csv.
Validation Criteria:
# Should contain the correct columns and minimum of 4 rows:
Import-Csv ~/ncarga/rbac-report.csv | Select-Object -First 5
# Expected columns: DisplayName, RoleDefinitionName, Scope, ObjectType
Step 9 β Implement and manage Azure Policyβ
Context: The audit identified that resources were being created without mandatory tags and in unauthorized regions. To ensure compliance from the start, the governance team requires location and naming policies before any deployment. Tasks:
[PowerShell] Assign the built-in policy Allowed locations (ID: e56962a6-4747-49cd-b67b-bf8b01975c4f) at the subscription scope using New-AzPolicyAssignment. Pass listOfAllowedLocations as an array with eastus and brazilsouth.
[PowerShell] Assign the built-in policy Require a tag and its value on resources (ID: 1e30110a-5ceb-460c-a204-c1c3969c6d62) at the subscription scope. Configure the required tag as Project with value Ancora.
[Portal] Confirm the assignments at: Policy β Compliance. Force evaluation with Start-AzPolicyComplianceScan if necessary.
Validation Criteria:
# Should return 2 lines, one for each assigned policy:
Get-AzPolicyAssignment |
Where-Object { $_.Properties.DisplayName -like "*Allowed*" -or $_.Properties.DisplayName -like "*tag*" } |
Select-Object Name, @{N='DisplayName';E={$_.Properties.DisplayName}}, @{N='Scope';E={$_.Properties.Scope}}
Step 10 β Configure resource locksβ
Context: The resource group ncarga-rg-financeiro contains sensitive billing data. The legal team requires that it cannot be accidentally deleted, even by administrators. The main network resources also need modification locks during the deployment period.
Tasks:
[PowerShell] Apply a CanNotDelete lock on the resource group ncarga-rg-financeiro with name ncarga-lock-financeiro and notes Protecao juridica LGPD using New-AzResourceLock.
[PowerShell] Create the resource group ncarga-rg-network in the eastus region with the tag Project=Ancora. Apply a ReadOnly lock with name ncarga-lock-network-ro.
[Portal] Navigate to: Resource groups β ncarga-rg-financeiro β Locks. Try to delete the resource group through the portal and confirm that the operation is blocked.
Validation Criteria:
# Should return LockLevel = CanNotDelete:
Get-AzResourceLock -ResourceGroupName "ncarga-rg-financeiro" |
Select-Object Name, @{N='LockLevel';E={$_.Properties.Level}}, @{N='Notes';E={$_.Properties.Notes}}
# Should return LockLevel = ReadOnly:
Get-AzResourceLock -ResourceGroupName "ncarga-rg-network" |
Select-Object Name, @{N='LockLevel';E={$_.Properties.Level}}
Step 11 β Apply and manage tags on resourcesβ
Context: The FinOps team has defined a tag taxonomy to track costs by project, environment, and responsible team. Tags need to be applied retroactively to existing resource groups and prospectively on all new resources.
Tasks:
[PowerShell] Apply the tag set below to ncarga-rg-financeiro and ncarga-rg-network using Update-AzTag with the Merge operation:
| Tag | Value |
|---|---|
| Project | Ancora |
| Environment | Production |
| Owner | ana.ferreira |
| CostCenter | TI-001 |
[PowerShell] Create the resource group ncarga-rg-compute in the eastus region with the four tags above using New-AzResourceGroup -Tag.
[PowerShell] List all resource groups with the tag Project=Ancora using Get-AzResourceGroup -Tag.
Validation Criteria:
# Should return the 4 tags:
(Get-AzResourceGroup -Name "ncarga-rg-network").Tags
# Should return Count >= 2:
Get-AzResource -TagName "Project" -TagValue "Ancora" | Measure-Object
Step 12 β Manage resource groupsβ
Context: The Γncora Project has grown and now requires a fourth resource group for storage resources. Additionally, the operations team needs to move a test resource created in the wrong resource group to the correct one, without recreating the resource.
Tasks:
[PowerShell] Create the resource group ncarga-rg-storage in the brazilsouth region with the four standard project tags.
[PowerShell] Create a temporary Storage Account (ncargatest001, SKU: Standard_LRS) in the resource group ncarga-rg-compute to simulate the resource in the wrong location.
[PowerShell] Move the Storage Account ncargatest001 from ncarga-rg-compute to ncarga-rg-storage using Move-AzResource. Capture the resource ID before the move with Get-AzStorageAccount.
Validation Criteria:
# Should return ResourceGroupName = ncarga-rg-storage:
Get-AzStorageAccount -Name "ncargatest001" -ResourceGroupName "ncarga-rg-storage" |
Select-Object StorageAccountName, ResourceGroupName
# Should return empty output:
Get-AzStorageAccount -ResourceGroupName "ncarga-rg-compute" |
Where-Object { $_.StorageAccountName -eq "ncargatest001" }
Step 13 β Manage subscriptionsβ
Context: The IT director requested a complete inventory of the current subscription before starting negotiations for a second subscription dedicated to the staging environment.
Tasks:
[PowerShell] Get details of the current subscription using Get-AzSubscription. Capture the Id, Name and TenantId in variables that will be used in the following steps.
[Portal] Confirm the name, ID and tenant at: Subscriptions β [your subscription] β Properties. Check payment status at: Cost Management + Billing β Subscriptions.
[PowerShell] Add the tag ProjectAncora=true directly to the subscription using Update-AzTag -ResourceId "/subscriptions/<id>" -Tag @{ProjectAncora="true"} -Operation Merge.
Validation Criteria:
# Should return ProjectAncora = true:
(Get-AzSubscription -SubscriptionId $subscriptionId).Tags
# Should return State = Enabled:
Get-AzSubscription | Select-Object Name, Id, TenantId, State
Step 14 β Manage costs with alerts, budgets and Azure Advisorβ
Context: The CFO established a monthly limit of USD 500 for the Γncora Project during the deployment phase. The FinOps team needs to configure automatic alerts and review Azure Advisor recommendations to optimize already created resources.
Tasks:
[Portal] Create the budget at: Cost Management + Billing β Budgets β Add
| Parameter | Value |
|---|---|
| Name | ncarga-budget-monthly |
| Reset period | Monthly |
| Budget amount | 500 USD |
| Alert threshold 1 | 80% (Actual) |
| Alert threshold 2 | 100% (Forecasted) |
| Alert email | ana.ferreira@<tenant>.onmicrosoft.com |
[Portal] Confirm the budget at: Cost Management β Cost alerts. Verify that ncarga-budget-monthly appears with Status = Active.
[Portal] Review recommendations at: Azure Advisor β All recommendations. Filter by subscription and record at least one recommendation in the Cost and Reliability categories.
Validation Criteria:
- Budget
ncarga-budget-monthlywith Amount = 500 USD and Status = Active. - Two alerts configured: 80% Actual and 100% Forecasted.
- Azure Advisor displays score for the subscription with at least one recommendation in Cost.
Step 15 β Configure management groupsβ
Context: With the Γncora Project subscription active, the architecture team defined a management group hierarchy to support the planned expansion: a production subscription (current) and a future staging one.
Tasks:
[PowerShell] Create a level 1 management group with ID ncarga-mg-root and display name NovaCarga Root using New-AzManagementGroup.
[PowerShell] Create a child management group with ID ncarga-mg-prod and name NovaCarga Production subordinated to ncarga-mg-root using the -ParentId parameter.
[PowerShell] Move the current subscription to the management group ncarga-mg-prod using New-AzManagementGroupSubscription -GroupId ncarga-mg-prod -SubscriptionId <id>.
Validation Criteria:
# Should return Name = ncarga-mg-prod with ParentId containing ncarga-mg-root:
Get-AzManagementGroup -GroupName "ncarga-mg-prod" -Expand -Recurse |
Select-Object Name, DisplayName, ParentId
# Should return your subscription listed under ncarga-mg-prod:
Get-AzManagementGroupSubscription -GroupId "ncarga-mg-prod" |
Select-Object DisplayName, Id
Domain 2 β Storageβ
Step 16 β Configure Azure Storage firewalls and virtual networksβ
Context: The storage account ncargatest001, moved to ncarga-rg-storage in Step 12, will be the official repository for NovaCarga's tax documents. Per audit requirement, unrestricted public access needs to be disabled.
Tasks:
[PowerShell] Disable public network access to storage account ncargatest001 using Update-AzStorageAccountNetworkRuleSet. Configure DefaultAction as Deny and Bypass as AzureServices,Logging,Metrics.
[PowerShell] Get your public IP with Invoke-RestMethod -Uri https://api.ipify.org. Add it as an exception in the firewall using Add-AzStorageAccountNetworkRule -IPAddressOrRange <your-ip>.
[Portal] Confirm at: Storage accounts β ncargatest001 β Networking. The Public network access field should display Enabled from selected virtual networks and IP addresses and your IP should appear in the exceptions list.
Validation Criteria:
# Should return Deny:
(Get-AzStorageAccountNetworkRuleSet -ResourceGroupName "ncarga-rg-storage" -AccountName "ncargatest001").DefaultAction
# Should return your IP with Action = Allow:
(Get-AzStorageAccountNetworkRuleSet -ResourceGroupName "ncarga-rg-storage" -AccountName "ncargatest001").IpRules
Step 17 β Create and use SAS tokensβ
Context: The TMS system needs to upload delivery receipts to storage without using account access keys. The security team approved the use of SAS tokens with restricted scope and short validity for this integration.
Tasks:
[PowerShell] Create a container called comprovantes in storage account ncargatest001 with private access using New-AzStorageContainer.
[PowerShell] Generate a container-level SAS token for comprovantes with the parameters:
| Parameter | Value |
|---|---|
| Permissions | Read, Write, List |
| Expiration | 2 hours from current time |
| Allowed protocol | HTTPS only |
Use New-AzStorageContainerSASToken. Capture the complete URL with the token.
[PowerShell] Test the SAS token by uploading a local text file to the comprovantes container using Set-AzStorageBlobContent with the context created from the SAS token, without using account keys.
Validation Criteria:
# Should return the test file with size > 0:
Get-AzStorageBlob -Container "comprovantes" -Context <account-context> |
Select-Object Name, Length
Step 18 β Configure Stored Access Policiesβ
Context: The development team identified that revoking individual SAS tokens is unfeasible in case of compromise. The solution is to use Stored Access Policies, which allow revoking an entire set of tokens without recreating them individually.
Tasks:
[PowerShell] Create a Stored Access Policy called ncarga-sap-comprovantes on the comprovantes container with permissions Read, Write, List and 30-day validity using New-AzStorageContainerStoredAccessPolicy.
[PowerShell] Generate a new SAS token linked to the policy ncarga-sap-comprovantes, omitting direct permission and expiration parameters β they will be inherited from the policy.
[PowerShell] Revoke the policy using Remove-AzStorageContainerStoredAccessPolicy and confirm that the linked SAS token fails when trying to list the container's blobs.
Validation Criteria:
# Before removal β should return Policy = ncarga-sap-comprovantes:
Get-AzStorageContainerStoredAccessPolicy -Container "comprovantes" -Context <context> |
Select-Object Policy, Permissions, ExpiryTime
# After removal β attempt to list blobs with linked SAS should return:
# 403 AuthorizationFailure error or similar
Step 19 β Manage storage access keysβ
Context: NovaCarga's security policy requires storage access key rotation every 90 days. This step documents and executes the rotation process without service interruption.
Tasks:
[PowerShell] Get the two access keys of storage account ncargatest001 using Get-AzStorageAccountKey. Record the current value of key1 as reference for post-rotation validation.
[PowerShell] Regenerate key1 using New-AzStorageAccountKey -KeyName key1. Confirm that the new value differs from the previously recorded one.
[Portal] Confirm the rotation at: Storage accounts β ncargatest001 β Security + networking β Access keys. Verify that key2 remains unchanged.
Validation Criteria:
# Should return 2 lines with key1 and key2:
$keys = Get-AzStorageAccountKey -ResourceGroupName "ncarga-rg-storage" -AccountName "ncargatest001"
$keys | Select-Object KeyName, Value
# key1 should have a different value from the one recorded before rotation
Step 20 β Configure identity-based access for Azure Filesβ
Context: The HR department needs a file share for onboarding and offboarding documents. Per audit requirement, access must be controlled by Microsoft Entra ID identity, without using storage keys.
Tasks:
[PowerShell] Create a new storage account called ncargatfiles001 in the brazilsouth region, resource group ncarga-rg-storage, SKU Standard_LRS, kind StorageV2 using New-AzStorageAccount.
[Portal] Enable identity-based authentication by navigating to: Storage accounts β ncargatfiles001 β File shares β Active Directory. Select Microsoft Entra Kerberos as the authentication method.
[PowerShell] Assign the role Storage File Data SMB Share Contributor to the group ncarga-ti at the scope of storage account ncargatfiles001 using New-AzRoleAssignment.
Validation Criteria:
# Should return ncarga-ti with Storage File Data SMB Share Contributor:
Get-AzRoleAssignment -Scope (Get-AzStorageAccount -ResourceGroupName "ncarga-rg-storage" -Name "ncargatfiles001").Id |
Where-Object { $_.RoleDefinitionName -like "*SMB*" } |
Select-Object DisplayName, RoleDefinitionName
Step 21 β Create and configure storage accountsβ
Context: The Γncora Project requires a main storage account for TMS tracking logs, configured with the security and performance parameters defined by the architecture team.
Tasks:
[PowerShell] Create the storage account ncargatms001 in resource group ncarga-rg-storage, region eastus, with the parameters:
| Parameter | Value |
|---|---|
| SKU | Standard_GRS |
| Kind | StorageV2 |
| AccessTier | Hot |
| MinimumTlsVersion | TLS1_2 |
| AllowBlobPublicAccess | $false |
| EnableHttpsTrafficOnly | $true |
[PowerShell] Disable account key access using Set-AzStorageAccount -AllowSharedKeyAccess $false, forcing the use of Entra ID identity for access.
[Portal] Confirm all parameters in: Storage accounts β ncargatms001 β Configuration. Verify that Secure transfer required is Enabled and Allow Blob public access is Disabled.
Validation Criteria:
# Should return all fields matching the defined parameters:
$sa = Get-AzStorageAccount -ResourceGroupName "ncarga-rg-storage" -Name "ncargatms001"
$sa | Select-Object StorageAccountName, Sku, Kind, AccessTier, MinimumTlsVersion, AllowBlobPublicAccess, EnableHttpsTrafficOnly
Step 22 β Configure Azure Storage redundancyβ
Context: The architecture team reviewed the RPO and RTO requirements for TMS data. Tracking logs are critical for regulatory audits, and reading in the secondary region is necessary for contingency reports.
Tasks:
[PowerShell] Verify the current redundancy of storage account ncargatms001 with Get-AzStorageAccount. Confirm that the SKU is Standard_GRS.
[PowerShell] Change the redundancy from Standard_GRS to Standard_RAGRS (Read-Access Geo-Redundant Storage) using Set-AzStorageAccount -SkuName Standard_RAGRS. This enables reading in the secondary region.
[Portal] Confirm the secondary region endpoint in: Storage accounts β ncargatms001 β Geo-replication. Note the secondary endpoint URL.
Validation Criteria:
# Should return Standard_RAGRS:
(Get-AzStorageAccount -ResourceGroupName "ncarga-rg-storage" -Name "ncargatms001").Sku.Name
# Should return populated secondary endpoint URLs:
(Get-AzStorageAccount -ResourceGroupName "ncarga-rg-storage" -Name "ncargatms001").SecondaryEndpoints
Step 23 β Configure object replicationβ
Context: The legal team requires that tax document images stored in the comprovantes container of storage ncargatest001 be automatically replicated to ncargatms001 in another region, for compliance and disaster recovery purposes.
Tasks:
[PowerShell] Enable blob versioning on storage accounts ncargatest001 and ncargatms001 β mandatory prerequisite for object replication.
[PowerShell] Enable Change Feed on storage account ncargatest001 (source) using Update-AzStorageAccount -EnableChangeFeed $true.
[PowerShell] Create an object replication rule from the comprovantes container (source: ncargatest001) to the comprovantes-replica container (destination: ncargatms001) using Set-AzStorageObjectReplicationPolicy. The filter should replicate only blobs with prefix fiscal/.
Validation Criteria:
# Should return the policy with SourceAccount = ncargatest001:
Get-AzStorageObjectReplicationPolicy -ResourceGroupName "ncarga-rg-storage" -StorageAccountName "ncargatms001" |
Select-Object PolicyId, SourceAccount, DestinationAccount
Step 24 β Configure storage account encryptionβ
Context: The security policy requires that data-at-rest encryption in storage ncargatms001 be managed by Customer-Managed Keys stored in Azure Key Vault, instead of Microsoft-managed keys.
Tasks:
[PowerShell] Create Azure Key Vault ncarga-kv-001 in resource group ncarga-rg-storage, region eastus, with EnableSoftDelete $true and EnablePurgeProtection $true using New-AzKeyVault.
[PowerShell] Create an RSA 2048 key named ncarga-key-storage in the Key Vault using Add-AzKeyVaultKey -Destination Software -KeyType RSA -Size 2048.
[PowerShell] Configure storage account ncargatms001 to use Customer-Managed Key with the ncarga-key-storage key from Key Vault ncarga-kv-001. Enable managed identity on the storage account and grant the Key Vault Crypto Service Encryption User permission to the managed identity before applying the CMK.
Validation Criteria:
# Should return KeyName = ncarga-key-storage:
(Get-AzStorageAccount -ResourceGroupName "ncarga-rg-storage" -Name "ncargatms001").Encryption.KeyVaultProperties
# Should return Microsoft.Keyvault:
(Get-AzStorageAccount -ResourceGroupName "ncarga-rg-storage" -Name "ncargatms001").Encryption.KeySource
Step 25 β Manage data with Azure Storage Explorer and AzCopyβ
Context: The operations team needs to transfer a batch of legacy tax documents to the comprovantes container of storage ncargatest001. The transfer must be auditable and efficient, using AzCopy with Microsoft Entra ID authentication.
AzCopy v10+ installed locally. Verify with: azcopy --version
Tasks:
[PowerShell / CLI] Login to AzCopy with Microsoft Entra ID using azcopy login --tenant-id <tenant-id>.
[PowerShell / CLI] Create the local folder ~/ncarga/fiscais/ with at least 3 text files simulating tax documents. Upload the entire folder to the comprovantes container in the path fiscal/2024/ using azcopy copy with the --recursive flag.
[Portal] Confirm the files in: Storage accounts β ncargatest001 β Storage browser β Blob containers β comprovantes β fiscal/2024/.
Validation Criteria:
# Should list the uploaded files with "Number of File Transfers: 3" at the end:
azcopy list "https://ncargatest001.blob.core.windows.net/comprovantes/fiscal/2024/"
Step 26 β Create and configure an Azure Files shareβ
Context: The HR department needs an SMB file share accessible by headquarters employees. The share will be mounted on Windows servers to be created in Step 37.
Tasks:
[PowerShell] Create the share ncarga-rh-share in storage account ncargatfiles001 with a 100 GiB quota and tier TransactionOptimized using New-AzRmStorageShare.
[PowerShell] Create the directories Admissoes, Demissoes and Ferias within the share using New-AzStorageDirectory for each one.
[Portal] Confirm the share, the 100 GiB quota and the three subdirectories in: Storage accounts β ncargatfiles001 β File shares β ncarga-rh-share. Copy the PowerShell mounting script available in Connect for future use.
Validation Criteria:
# Should return QuotaGiB = 100:
Get-AzRmStorageShare -ResourceGroupName "ncarga-rg-storage" -StorageAccountName "ncargatfiles001" -Name "ncarga-rh-share" |
Select-Object Name, QuotaGiB, AccessTier
# Should return 3 items: Admissoes, Demissoes, Ferias:
Get-AzStorageFile -ShareName "ncarga-rh-share" -Context <context> |
Select-Object Name
Step 27 β Create and configure an Azure Blob Storage containerβ
Context: The tracking system generates GPS images and telemetry in high volume. Two Blob containers with distinct configurations are needed to separate raw data from processed data.
Tasks:
[PowerShell] Create two containers in storage account ncargatms001 with private access using New-AzStorageContainer:
| Container | Description |
|---|---|
| telemetria-raw | Raw GPS and sensor data |
| telemetria-processada | Processed and aggregated data |
[Portal] Confirm the two containers in: Storage accounts β ncargatms001 β Containers. Both should display Private access.
Validation Criteria:
# Should return 2 containers with PublicAccess = Off:
Get-AzStorageContainer -Context <contexto-ncargatms001> |
Where-Object { $_.Name -like "telemetria*" } |
Select-Object Name, PublicAccess
Step 28 β Configure storage tiersβ
Context: Telemetry data has a well-defined lifecycle: frequently accessed in the first 30 days and rarely after 90 days. The FinOps team approved manual tier changes for some blobs and automatic policy implementation.
Tasks:
[PowerShell] Upload a test blob named gps-sample-001.json to the telemetria-raw container in storage ncargatms001 in the Hot tier.
[PowerShell] Change the tier of blob gps-sample-001.json to Cool using Set-AzStorageBlobTier. Confirm with Get-AzStorageBlob.
[Portal] Create the lifecycle rule ncarga-lifecycle-telemetria in: Storage accounts β ncargatms001 β Lifecycle management. Configure: move to Cool after 30 days and to Archive after 90 days for blobs in the telemetria-raw container.
Validation Criteria:
# Should return Cool:
(Get-AzStorageBlob -Container "telemetria-raw" -Blob "gps-sample-001.json" -Context <context>).ICloudBlob.Properties.StandardBlobTier
# In portal: ncarga-lifecycle-telemetria rule active with tierToCool (30d) and tierToArchive (90d) actions
Step 29 β Configure soft delete for blobs and containersβ
Context: The legal team identified that accidentally deleted telemetry data may be needed in audits. The retention policy defines that deleted blobs and containers should be recoverable for 30 days.
Tasks:
[PowerShell] Enable soft delete for blobs in storage account ncargatms001 with 30-day retention using Enable-AzStorageBlobDeleteRetentionPolicy -RetentionDays 30.
[PowerShell] Enable soft delete for containers with 30-day retention using Enable-AzStorageContainerDeleteRetentionPolicy -RetentionDays 30.
[PowerShell] Test soft delete: delete blob gps-sample-001.json from container telemetria-raw and list blobs with Get-AzStorageBlob -IncludeDeleted to confirm the blob appears with Deleted state.
Validation Criteria:
# Should return Enabled = True, Days = 30:
(Get-AzStorageServiceProperty -ServiceType Blob -Context <context>).DeleteRetentionPolicy
# Should return gps-sample-001.json with IsDeleted = True:
Get-AzStorageBlob -Container "telemetria-raw" -Context <context> -IncludeDeleted |
Where-Object { $_.IsDeleted -eq $true } |
Select-Object Name, IsDeleted
Step 30 β Configure snapshots and soft delete for Azure Filesβ
Context: The ncarga-rh-share share contains admission documents that need protection against accidental modifications and deletions. Snapshots and soft delete ensure file recoverability.
Tasks:
[PowerShell] Enable soft delete for the ncarga-rh-share share in storage account ncargatfiles001 with 14-day retention using Update-AzStorageFileServiceProperty.
[PowerShell] Create a manual snapshot of the share using $share.Snapshot() via storage context. Capture the generated SnapshotTime.
[Portal] Confirm the snapshot in: Storage accounts β ncargatfiles001 β File shares β ncarga-rh-share β Snapshots. Also verify that Soft delete is enabled in the File service properties.
Validation Criteria:
# Should return Enabled = True, Days = 14:
(Get-AzStorageFileServiceProperty -ResourceGroupName "ncarga-rg-storage" -StorageAccountName "ncargatfiles001").ShareDeleteRetentionPolicy
# Should return entry with filled SnapshotTime:
Get-AzRmStorageShare -ResourceGroupName "ncarga-rg-storage" -StorageAccountName "ncargatfiles001" -Name "ncarga-rh-share" -GetShareUsage |
Select-Object Name, SnapshotTime
Step 31 β Configure blob lifecycle managementβ
Context: The lifecycle policy created in Step 28 needs to be expanded to cover the telemetria-processada container and add an automatic deletion action for blobs older than 365 days.
Tasks:
[PowerShell] Get the existing lifecycle policy from storage account ncargatms001 using Get-AzStorageAccountManagementPolicy.
[PowerShell] Add a new rule to the policy covering the telemetria-processada container with the actions:
- Move to
Coolafter 60 days - Move to
Archiveafter 180 days - Delete blobs after 365 days
Use Set-AzStorageAccountManagementPolicy with the rule object added to the existing array.
[Portal] Confirm both rules in: Storage accounts β ncargatms001 β Lifecycle management. Both should be active.
Validation Criteria:
# Should return 2 rules with Enabled = True:
(Get-AzStorageAccountManagementPolicy -ResourceGroupName "ncarga-rg-storage" -StorageAccountName "ncargatms001").Rules |
Select-Object Name, Enabled
Step 32 β Configure blob versioningβ
Context: Tax documents in the comprovantes container may be updated by ERP and TMS systems. The legal team requires all previous versions to be kept for audit purposes.
Tasks:
[PowerShell] Confirm that blob versioning is enabled in storage account ncargatest001 (partially enabled in Step 23). Use Enable-AzStorageBlobVersioning if necessary.
[PowerShell] Upload a blob named nf-001.json with content {"status":"emitida"} to the comprovantes container. Then, update the same blob with {"status":"cancelada"} β this will create a new version.
[PowerShell] List blob versions using Get-AzStorageBlob -Container comprovantes -Blob nf-001.json -IncludeVersion. Confirm at least two versions with distinct VersionId.
Validation Criteria:
# Should return at least 2 lines, one with IsLatestVersion = True:
Get-AzStorageBlob -Container "comprovantes" -Blob "nf-001.json" -Context <context> -IncludeVersion |
Select-Object Name, VersionId, IsLatestVersion
Domain 3 β Infrastructure as Code (IaC)β
bicep --version β Install the Bicep CLI before starting this section.
Step 33 β Interpret ARM templates and Bicep filesβ
Context: NovaCarga's architecture team has standardized the use of Bicep for all future deployments. Before creating new resources via IaC, the engineer needs to analyze an existing Bicep template and identify the declared parameters, resources, and dependencies.
Tasks:
[IaC] Analyze the Bicep file below without executing it. Identify and answer in writing: which resources will be created, what is the dependency between them, which parameters are mandatory, and what would be the default value of location if not provided.
// Template for review β NovaCarga Anchor Project
param location string = resourceGroup().location
param storageAccountName string
param keyVaultName string
@secure()
param adminPassword string
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: storageAccountName
location: location
sku: { name: 'Standard_LRS' }
kind: 'StorageV2'
}
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
name: keyVaultName
location: location
properties: {
sku: { family: 'A', name: 'standard' }
tenantId: subscription().tenantId
accessPolicies: []
enableSoftDelete: true
}
dependsOn: [storageAccount]
}
[PowerShell] Export the storage account ncargatest001 as an ARM template using Export-AzResourceGroup -ResourceGroupName ncarga-rg-storage -Resource <storage-id>. Save the exported JSON locally.
[IaC] Convert the exported ARM template to Bicep using bicep decompile <file>.json. Confirm that the .bicep file was generated without errors.
Validation Criteria:
# Should list the generated .bicep file:
ls *.bicep
# Should compile without errors:
bicep build <decompiled-file>.bicep
Step 34 β Modify an existing ARM templateβ
Context: The operations team identified that the ARM template exported in Step 33 does not include the mandatory HTTPS configuration. The engineer needs to modify the template before reusing it in automated deployments.
Tasks:
[IaC] In the ARM JSON file exported in Step 33, locate the resource of type Microsoft.Storage/storageAccounts within the resources array. Add the property supportsHttpsTrafficOnly: true within properties without removing any existing properties.
[IaC] Add an environment parameter of type string with allowedValues: ['dev', 'staging', 'prod'] in the template's parameters section.
[PowerShell] Validate the modified template:
Test-AzResourceGroupDeployment -ResourceGroupName "ncarga-rg-storage" `
-TemplateFile <path-to-modified-json> `
-environment "prod" `
-storageAccountName "ncargatvalid001"
Validation Criteria:
# Should return output without validation errors:
Test-AzResourceGroupDeployment -ResourceGroupName "ncarga-rg-storage" `
-TemplateFile <modified-file>.json `
-environment "prod" `
-storageAccountName "ncargatvalid001"
Step 35 β Modify an existing Bicep fileβ
Context: The Bicep file generated in Step 33 needs to be expanded to include a reference to the existing Key Vault and add an output with the storage account URI, allowing other Bicep modules to reference the created resources.
Tasks:
[IaC] Add an output block to the .bicep file that exposes the storage account's blobEndpoint with the name storageEndpoint of type string.
[IaC] Add a reference to the existing Key Vault ncarga-kv-001 using an existing scoped resource of type Microsoft.KeyVault/vaults@2023-07-01.
[IaC] Compile the modified Bicep file with bicep build and confirm no errors. Do not deploy at this step.
Validation Criteria:
# Should generate the corresponding .json file without errors:
bicep build <modified-file>.bicep
# Should find the storageEndpoint key:
cat <file>.json | grep -i "storageEndpoint"
Step 36 β Deploy resources with Bicep templateβ
Context: The automation team approved the first IaC infrastructure deployment in Project Γncora. The Bicep developed in previous steps will be used to create an audit storage account without manual interaction.
Tasks:
[IaC] Create the file ncarga-audit-storage.bicep filling in the indicated fields:
// Fill in the fields marked with <FILL_IN>
param location string = <FILL_IN> // brazilsouth
param storageAccountName string = <FILL_IN> // ncargataudit001
param tags object = <FILL_IN> // the 4 standard project tags
resource auditStorage 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: <FILL_IN>
location: <FILL_IN>
tags: <FILL_IN>
sku: { name: <FILL_IN> } // Standard_LRS
kind: <FILL_IN> // StorageV2
properties: {
supportsHttpsTrafficOnly: <FILL_IN> // true
minimumTlsVersion: <FILL_IN> // TLS1_2
allowBlobPublicAccess: <FILL_IN> // false
}
}
output storageId string = <FILL_IN>
output storageName string = <FILL_IN>
[PowerShell] Compile the Bicep and deploy using New-AzResourceGroupDeployment with -TemplateFile. Name the deployment as ncarga-deploy-audit-storage.
[PowerShell] Capture the deployment output values:
(Get-AzResourceGroupDeployment -ResourceGroupName "ncarga-rg-storage" -Name "ncarga-deploy-audit-storage").Outputs
Validation Criteria:
# Should return ProvisioningState = Succeeded:
Get-AzResourceGroupDeployment -ResourceGroupName "ncarga-rg-storage" -Name "ncarga-deploy-audit-storage" |
Select-Object DeploymentName, ProvisioningState
# Should return Location = brazilsouth:
Get-AzStorageAccount -ResourceGroupName "ncarga-rg-storage" -Name "ncargataudit001" |
Select-Object StorageAccountName, Location
Domain 4 β Compute and Containersβ
Step 37 β Create a virtual machineβ
Context: NovaCarga's legacy WMS system needs to be hosted on a Windows VM in Azure. The server will be created without a public IP β administrative access will be done exclusively via Azure Bastion, configured in Step 61.
The ReadOnly lock on ncarga-rg-network created in Step 10 needs to be temporarily removed to create network resources in this step. Recreate it after completion.
Tasks:
[PowerShell] Create the virtual network ncarga-vnet-compute in resource group ncarga-rg-network with address space 10.10.0.0/16 and subnet snet-compute with range 10.10.1.0/24 using New-AzVirtualNetwork and Add-AzVirtualNetworkSubnetConfig.
[PowerShell] Create the VM ncarga-vm-wms01 with the parameters:
| Parameter | Value |
|---|---|
| Resource Group | ncarga-rg-compute |
| Region | eastus |
| Image | Win2022Datacenter |
| Size | Standard_D2s_v3 |
| Subnet | snet-compute in ncarga-vnet-compute |
| Public IP | None |
| Authentication | Password (admin: ncargaadmin) |
Use New-AzVM. Capture the VM Id at the end.
[PowerShell] Confirm that the associated NIC has no public IP:
(Get-AzNetworkInterface -ResourceGroupName "ncarga-rg-compute" |
Where-Object { $_.VirtualMachine.Id -like "*ncarga-vm-wms01*" }).IpConfigurations.PublicIpAddress
# Expected result: $null
Validation Criteria:
# Should return ProvisioningState = Succeeded:
Get-AzVM -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-vm-wms01" |
Select-Object Name, Location, @{N='ProvisioningState';E={$_.ProvisioningState}}
Step 38 β Configure encryption at host for VMsβ
Context: The security team requires that all temporary data from cache disks and OS disk of VMs be encrypted on the Azure compute host itself. This configuration must be enabled on VM ncarga-vm-wms01.
Tasks:
[PowerShell] Check if the EncryptionAtHost feature is enabled in the subscription using Get-AzProviderFeature -FeatureName EncryptionAtHost -ProviderNamespace Microsoft.Compute. If the state is NotRegistered, register it with Register-AzProviderFeature and wait.
[PowerShell] Stop the VM ncarga-vm-wms01 with Stop-AzVM -Force. Wait for Deallocated status.
[PowerShell] Enable Encryption at Host on the VM using Update-AzVM with SecurityProfile.EncryptionAtHost = $true. Restart the VM after configuration.
Validation Criteria:
# Should return True:
(Get-AzVM -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-vm-wms01").SecurityProfile.EncryptionAtHost
# Should return PowerState/running:
Get-AzVM -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-vm-wms01" -Status |
Select-Object -ExpandProperty Statuses | Where-Object { $_.Code -like "PowerState*" }
Step 39 β Move a VM to another resource groupβ
Context: After reviewing the resource group structure, the architecture team decided that all production VMs should be in a dedicated resource group called ncarga-rg-vms. VM ncarga-vm-wms01 needs to be moved without recreation.
Tasks:
[PowerShell] Create the resource group ncarga-rg-vms in region eastus with the four standard project tags.
[PowerShell] Identify all dependent resources of VM ncarga-vm-wms01 (disks, NICs, etc.) using Get-AzResource -ResourceGroupName ncarga-rg-compute | Where-Object { $_.Name -like "*wms01*" }. Capture all their IDs.
[PowerShell] Move the VM and all its dependent resources to ncarga-rg-vms using Move-AzResource -ResourceId @(<list-of-ids>) -DestinationResourceGroupName ncarga-rg-vms.
Validation Criteria:
# Should return ResourceGroupName = ncarga-rg-vms:
Get-AzVM -ResourceGroupName "ncarga-rg-vms" -Name "ncarga-vm-wms01" |
Select-Object Name, ResourceGroupName
# Should return empty output:
Get-AzVM -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-vm-wms01" -ErrorAction SilentlyContinue
Step 40 β Manage VM sizesβ
Context: The WMS system experiences peak load at month-end. The operations team requested temporary resizing of VM ncarga-vm-wms01 to a size with 4+ vCPUs and 16+ GB of RAM.
Tasks:
[PowerShell] List available VM sizes in region eastus with 4+ vCPUs and 8+ GB of RAM using Get-AzVMSize -Location eastus. Identify Standard_D4s_v3 as a suitable option.
[PowerShell] Stop VM ncarga-vm-wms01 (deallocate). Change the size to Standard_D4s_v3 by modifying the HardwareProfile.VmSize property and applying with Update-AzVM.
[PowerShell] Start the VM and confirm the new size with Get-AzVM.
Validation Criteria:
# Should return Standard_D4s_v3:
(Get-AzVM -ResourceGroupName "ncarga-rg-vms" -Name "ncarga-vm-wms01").HardwareProfile.VmSize
Step 41 β Manage VM disksβ
Context: The WMS's local SQLite database is growing and the current data disk is getting small. The IT team needs to add a dedicated 128 GB data disk for database files.
Tasks:
[PowerShell] Create the managed disk ncarga-disk-wms-data01 in resource group ncarga-rg-vms, region eastus, with 128 GiB and SKU Premium_LRS using New-AzDisk.
[PowerShell] Attach the disk to VM ncarga-vm-wms01 as data disk at LUN 0 using Add-AzVMDataDisk and Update-AzVM.
[PowerShell] Confirm the attachment with Get-AzVM checking the StorageProfile.DataDisks field.
Validation Criteria:
# Should return Name = ncarga-disk-wms-data01, Lun = 0, DiskSizeGB = 128:
(Get-AzVM -ResourceGroupName "ncarga-rg-vms" -Name "ncarga-vm-wms01").StorageProfile.DataDisks |
Select-Object Name, Lun, DiskSizeGB, ManagedDisk
Step 42 β Deploy VMs in Availability Zones and Availability Setsβ
Context: The TMS system requires high availability. The architecture team defined that TMS VMs should be deployed in different Availability Zones to ensure 99.99% SLA.
Tasks:
[PowerShell] Create VM ncarga-vm-tms01 in resource group ncarga-rg-vms with image UbuntuLTS, size Standard_D2s_v3, zone 1, subnet snet-compute, no public IP, SSH authentication.
[PowerShell] Create VM ncarga-vm-tms02 with the same parameters, but in zone 2. Both VMs should be in subnet snet-compute.
[PowerShell] Confirm that each VM is in a different zone:
Get-AzVM -ResourceGroupName "ncarga-rg-vms" |
Where-Object { $_.Name -like "*tms*" } |
Select-Object Name, Zones
# Expected: ncarga-vm-tms01 with Zones = {1}, ncarga-vm-tms02 with Zones = {2}
Validation Criteria:
# Should return Zones = {1} for tms01 and Zones = {2} for tms02:
Get-AzVM -ResourceGroupName "ncarga-rg-vms" |
Where-Object { $_.Name -like "*tms*" } |
Select-Object Name, Zones
Step 43 β Deploy and configure Azure Virtual Machine Scale Setsβ
Context: The real-time tracking service receives traffic spikes during business hours. The architecture team approved the use of Virtual Machine Scale Sets to automatically scale the GPS event processing layer.
Tasks:
[PowerShell] Create the VMSS ncarga-vmss-tracker in resource group ncarga-rg-vms, region eastus, with image UbuntuLTS, size Standard_D2s_v3, initial capacity of 2 instances, subnet snet-compute, upgrade policy Automatic and zones 1,2,3 using New-AzVmss.
[PowerShell] Configure the autoscaling policy using New-AzAutoscaleSetting:
- Scale-out: Average CPU > 70% for 5 min β add 1 instance
- Scale-in: Average CPU < 30% for 10 min β remove 1 instance
- Minimum: 2 instances, Maximum: 10 instances
[Portal] Confirm the 2 active instances and autoscale policy at: Virtual Machine Scale Sets β ncarga-vmss-tracker β Instances and Scaling.
Validation Criteria:
# Should return Capacity = 2, Tier = Standard_D2s_v3:
Get-AzVmss -ResourceGroupName "ncarga-rg-vms" -VMScaleSetName "ncarga-vmss-tracker" |
Select-Object Name, @{N='Capacity';E={$_.Sku.Capacity}}, @{N='Tier';E={$_.Sku.Name}}
# Should return Enabled = True:
Get-AzAutoscaleSetting -ResourceGroupName "ncarga-rg-vms" |
Where-Object { $_.Name -like "*tracker*" } |
Select-Object Name, Enabled
Step 44 β Create and manage an Azure Container Registryβ
Context: The new tracking platform is developed as microservices in containers. The DevOps team needs a private registry in Azure to store and version Docker images before deploying them to clusters.
Docker Desktop installed and running. Check with: docker --version
Tasks:
[PowerShell] Create the Azure Container Registry ncargatregistry001 in resource group ncarga-rg-compute, region eastus, SKU Standard using New-AzContainerRegistry.
[PowerShell] Enable admin user with Update-AzContainerRegistry -EnableAdminUser $true. Get credentials using Get-AzContainerRegistryCredential.
[PowerShell / CLI] Login to the registry via Docker CLI with docker login ncargatregistry001.azurecr.io. Create a local test image (FROM alpine:latest), tag it and push to ncargatregistry001.azurecr.io/rastreamento:v1.0.
Validation Criteria:
# Should return "rastreamento" listed as repository:
Get-AzContainerRegistryRepository -RegistryName "ncargatregistry001" |
Select-Object -ExpandProperty Name
# Should return Sku = Standard, AdminUserEnabled = True:
Get-AzContainerRegistry -ResourceGroupName "ncarga-rg-compute" -Name "ncargatregistry001" |
Select-Object Name, Sku, AdminUserEnabled
Step 45 β Provision a container with Azure Container Instancesβ
Context: To validate the tracking:v1.0 image published in Step 44, the QA team needs an ephemeral testing environment. Azure Container Instances will allow running the container without managing orchestration infrastructure.
Tasks:
[PowerShell] Create the Container Instance ncarga-aci-rastreamento in resource group ncarga-rg-compute, region eastus, with:
| Parameter | Value |
|---|---|
| Image | ncargatregistry001.azurecr.io/rastreamento:v1.0 |
| CPU | 1 |
| Memory | 1.5 GiB |
| OS | Linux |
| Restart policy | Never |
Use New-AzContainerGroup with the registry credentials obtained in Step 44.
[PowerShell] Wait for the container to reach the Terminated or Running state with Get-AzContainerGroup. Capture the logs with Get-AzContainerInstanceLog.
[Portal] Confirm the log output at: Container instances β ncarga-aci-rastreamento β Containers β Logs.
Validation Criteria:
# Should return the correct image:
Get-AzContainerGroup -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-aci-rastreamento" |
Select-Object Name, Location, @{N='State';E={$_.InstanceViewState}}, @{N='Image';E={$_.Containers[0].Image}}
Step 46 β Provision a container with Azure Container Appsβ
Context: After validating the image with ACI in Step 45, the DevOps team decided to host the tracking service in production on Azure Container Apps, which offers automatic scaling based on HTTP events.
Tasks:
[CLI] Create the Container Apps Environment ncarga-cae-prod in resource group ncarga-rg-compute, region eastus using az containerapp env create.
[CLI] Create the Container App ncarga-ca-rastreamento in environment ncarga-cae-prod with:
| Parameter | Value |
|---|---|
| Image | ncargatregistry001.azurecr.io/rastreamento:v1.0 |
| CPU | 0.5 |
| Memory | 1Gi |
| Min replicas | 1 |
| Max replicas | 5 |
| Ingress | External, port 80 |
[CLI] Get the Container App URL with az containerapp show and confirm that the endpoint responds.
Validation Criteria:
# Should return URL in *.azurecontainerapps.io format:
az containerapp show --name ncarga-ca-rastreamento --resource-group ncarga-rg-compute \
--query "properties.configuration.ingress.fqdn" -o tsv
# Should return Running:
az containerapp show --name ncarga-ca-rastreamento --resource-group ncarga-rg-compute \
--query "properties.runningStatus" -o tsv
Step 47 β Manage container size and scalingβ
Context: The Container App ncarga-ca-rastreamento needs a scaling policy based on HTTP requests, aligned with the identified usage pattern: traffic peaks during business hours.
Tasks:
[CLI] Update the Container App to add an HTTP-based scaling rule: when the number of concurrent requests per replica exceeds 50, new replicas should be created. Use az containerapp update --scale-rule-name http-scale --scale-rule-type http.
[CLI] Update the Container App resource limits to --cpu 1.0 --memory 2Gi using az containerapp update.
[Portal] Confirm the scaling rules and resource limits at: Container Apps β ncarga-ca-rastreamento β Scale and replicas.
Validation Criteria:
# Should return minReplicas = 1, maxReplicas = 5 and http-scale rule present:
az containerapp show --name ncarga-ca-rastreamento --resource-group ncarga-rg-compute \
--query "properties.template.scale" -o json
# Should return cpu = "1.0", memory = "2Gi":
az containerapp show --name ncarga-ca-rastreamento --resource-group ncarga-rg-compute \
--query "properties.template.containers[0].resources" -o json
Domain 5 β App Serviceβ
Step 48 β Create and configure an App Service Planβ
Context: NovaCarga's customer portal, a web application for querying delivery status, will be hosted on Azure App Service. The App Service Plan will determine the computational resources available for the application.
App Service P1v3 generates ~USD 0.16/h. Reduce to F1 between sessions if necessary.
Tasks:
[PowerShell] Create the App Service Plan ncarga-asp-web in resource group ncarga-rg-compute, region brazilsouth, with SKU P1v3, OS Linux and 1 worker using New-AzAppServicePlan.
[Portal] View available tiers at: App Service plans β ncarga-asp-web β Scale up (App Service plan). Do not change the tier at this time.
[PowerShell] Confirm creation with Get-AzAppServicePlan verifying the Sku.Name and Kind fields.
Validation Criteria:
# Should return Sku = P1v3, OS = linux, NumberOfWorkers = 1:
Get-AzAppServicePlan -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-asp-web" |
Select-Object Name, @{N='Sku';E={$_.Sku.Name}}, @{N='OS';E={$_.Kind}}, NumberOfWorkers
Step 49 β Configure scaling for App Service Planβ
Context: The customer portal has traffic concentrated during business hours. The FinOps team approved automatic scaling of the App Service Plan based on CPU metrics to optimize cost outside peak hours.
Tasks:
[Portal] Enable autoscale at: App Service plans β ncarga-asp-web β Scale out (App Service plan). Create the profile ncarga-asp-autoscale with minimum 1, maximum 3 and default 1 instance.
[Portal] Add two rules to the profile:
- Scale-out: Average CPU > 70% for 5 min β increase 1 instance
- Scale-in: Average CPU < 25% for 10 min β decrease 1 instance
[PowerShell] Confirm the configuration with Get-AzAutoscaleSetting -ResourceGroupName ncarga-rg-compute verifying that the target resource is the App Service Plan ncarga-asp-web.
Validation Criteria:
# Should return Enabled = True with target ncarga-asp-web:
Get-AzAutoscaleSetting -ResourceGroupName "ncarga-rg-compute" |
Where-Object { $_.TargetResourceUri -like "*ncarga-asp-web*" } |
Select-Object Name, Enabled
Step 50 β Create an App Serviceβ
Context: With the App Service Plan provisioned, the development team needs to create the Web App that will host the delivery status query portal.
Tasks:
[PowerShell] Create the Web App ncarga-webapp-portal in App Service Plan ncarga-asp-web, resource group ncarga-rg-compute, runtime NODE|18-lts (Linux) using New-AzWebApp.
[PowerShell] Configure the application settings with Set-AzWebApp -AppSettings:
| Key | Value |
|---|---|
| ENVIRONMENT | production |
| STORAGE_ACCOUNT | ncargatms001 |
| PROJECT | Ancora |
[Portal] Copy the default URL at: App Services β ncarga-webapp-portal β Overview. Confirm that the site responds with the default Node.js page.
Validation Criteria:
# Should return State = Running with DefaultHostName filled:
Get-AzWebApp -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-webapp-portal" |
Select-Object Name, State, DefaultHostName
# Should return Value = production:
(Get-AzWebApp -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-webapp-portal").SiteConfig.AppSettings |
Where-Object { $_.Name -eq "ENVIRONMENT" } | Select-Object Name, Value
Step 51 β Configure certificates and TLS for App Serviceβ
Context: The customer portal must use mandatory HTTPS. The security team requires that HTTP connections be redirected to HTTPS and that the minimum TLS version be 1.2.
Tasks:
[PowerShell] Enable HTTPS redirection on Web App ncarga-webapp-portal using Set-AzWebApp -HttpsOnly $true.
[PowerShell] Configure the minimum TLS version to 1.2 on the Web App using Set-AzWebApp with the MinTlsVersion parameter.
[Portal] Confirm at: App Services β ncarga-webapp-portal β TLS/SSL settings
- HTTPS Only: On
- Minimum Inbound TLS Version: 1.2
Validation Criteria:
$webapp = Get-AzWebApp -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-webapp-portal"
# Should return True:
$webapp.HttpsOnly
# Should return 1.2:
$webapp.SiteConfig.MinTlsVersion
Step 52 β Configure backup for App Serviceβ
Context: The customer portal must have automatic daily backup for recovery in case of deployment failure or improper configuration changes. The backup will be stored in the storage account ncargataudit001.
Tasks:
[Portal] Configure backup at: App Services β ncarga-webapp-portal β Backups
| Parameter | Value |
|---|---|
| Storage account | ncargataudit001 |
| Container | appservice-backups (create new) |
| Frequency | Daily |
| Time | 02:00 UTC |
| Retention | 30 days |
[Portal] Trigger a manual backup by clicking Backup Now and wait for completion.
[PowerShell] List backups with Get-AzWebAppBackupList and confirm that the manual backup appears with Succeeded status.
Validation Criteria:
# Should return Succeeded = True with FinishedTimeUtc filled:
Get-AzWebAppBackupList -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-webapp-portal" |
Select-Object BackupName, StorageAccountUrl, Succeeded, FinishedTimeUtc |
Sort-Object FinishedTimeUtc -Descending |
Select-Object -First 1
Step 53 β Configure deployment slots for App Serviceβ
Context: The development team adopted the Blue-Green deployment pattern for the customer portal. A staging slot will allow new versions to be tested in production without affecting users.
Tasks:
[PowerShell] Create the deployment slot staging in Web App ncarga-webapp-portal using New-AzWebAppSlot.
[Portal] Configure at: App Services β ncarga-webapp-portal β Deployment slots β staging
- Application setting
SLOT_NAME=stagingas slot setting (not swappable) - Application setting
ENVIRONMENT=stagingas swappable setting
[PowerShell] Execute the swap between slots with Switch-AzWebAppSlot -SourceSlotName staging -DestinationSlotName production. Confirm that the production slot now has the setting ENVIRONMENT=staging.
Validation Criteria:
# Should return State = Running:
Get-AzWebAppSlot -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-webapp-portal" -Slot "staging" |
Select-Object Name, State
# After swap β should return Value = staging:
(Get-AzWebApp -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-webapp-portal").SiteConfig.AppSettings |
Where-Object { $_.Name -eq "ENVIRONMENT" } | Select-Object Value
Domain 6 β Networksβ
Step 54 β Create and configure virtual networks and subnetsβ
Context: The Projeto Γncora network infrastructure needs to be expanded to support segmentation by workload function. A second virtual network will be created for storage and service resources, with subnets dedicated by resource type.
Tasks:
[PowerShell] Create the VNet ncarga-vnet-services in resource group ncarga-rg-network, region brazilsouth, with address space 10.20.0.0/16 and the subnets:
| Subnet | Range |
|---|---|
| snet-storage | 10.20.1.0/24 |
| snet-web | 10.20.2.0/24 |
| AzureBastionSubnet | 10.20.0.0/27 (exact name required) |
[PowerShell] Create the NSG ncarga-nsg-web and associate it to subnet snet-web. Add inbound rules allowing HTTP (80) and HTTPS (443) from any origin, and blocking all other traffic with lower priority.
[PowerShell] Confirm that the NSG is associated to subnet snet-web with Get-AzVirtualNetworkSubnetConfig.
Validation Criteria:
# Should return the 3 subnets with correct ranges:
(Get-AzVirtualNetwork -ResourceGroupName "ncarga-rg-network" -Name "ncarga-vnet-services").Subnets |
Select-Object Name, AddressPrefix
# Should return the ID of ncarga-nsg-web:
(Get-AzVirtualNetworkSubnetConfig -Name "snet-web" -VirtualNetwork (Get-AzVirtualNetwork -Name "ncarga-vnet-services" -ResourceGroupName "ncarga-rg-network")).NetworkSecurityGroup.Id
Step 55 β Create and configure virtual network peeringβ
Context: The WMS and TMS VMs in ncarga-vnet-compute need to access storage accounts protected by private endpoints in ncarga-vnet-services. Peering between the two virtual networks is the approved connectivity solution.
Tasks:
[PowerShell] Create peering from ncarga-vnet-compute to ncarga-vnet-services using Add-AzVirtualNetworkPeering with AllowForwardedTraffic enabled.
[PowerShell] Create reciprocal peering from ncarga-vnet-services to ncarga-vnet-compute with the same parameters. Peering is only functional when both sides are configured.
[PowerShell] Confirm that both peerings have Connected state using Get-AzVirtualNetworkPeering.
Validation Criteria:
# Both should return PeeringState = Connected:
Get-AzVirtualNetworkPeering -ResourceGroupName "ncarga-rg-network" -VirtualNetworkName "ncarga-vnet-compute" |
Select-Object Name, PeeringState
Get-AzVirtualNetworkPeering -ResourceGroupName "ncarga-rg-network" -VirtualNetworkName "ncarga-vnet-services" |
Select-Object Name, PeeringState
Step 56 β Configure public IPsβ
Context: The public Load Balancer that will be created in Step 65 for the customer portal needs a static public IP with custom DNS. This IP will be announced to customers and cannot change after deployment.
Tasks:
[PowerShell] Create the public IP ncarga-pip-lb in resource group ncarga-rg-network, region brazilsouth, with:
| Parameter | Value |
|---|---|
| SKU | Standard |
| Allocation method | Static |
| DNS label | ncarga-portal |
| Version | IPv4 |
Use New-AzPublicIpAddress.
[PowerShell] Capture the value of the IpAddress field with Get-AzPublicIpAddress. This value will be used in Step 65.
[Portal] Confirm the generated DNS name label at: Public IP addresses β ncarga-pip-lb β Configuration. The FQDN should be ncarga-portal.<region>.cloudapp.azure.com.
Validation Criteria:
# Should return IpAddress filled, PublicIpAllocationMethod = Static, DnsLabel = ncarga-portal:
$pip = Get-AzPublicIpAddress -ResourceGroupName "ncarga-rg-network" -Name "ncarga-pip-lb"
$pip | Select-Object Name, IpAddress, PublicIpAllocationMethod, @{N='DnsLabel';E={$_.DnsSettings.DomainNameLabel}}
Step 57 β Configure user-defined routes (UDR)β
Context: The security team determined that all outbound traffic from VMs to the internet must pass through a Network Virtual Appliance (NVA) firewall. A UDR will be configured on subnet snet-compute to force this routing.
Tasks:
[PowerShell] Create the Route Table ncarga-rt-compute in resource group ncarga-rg-network with tag Project=Ancora using New-AzRouteTable.
[PowerShell] Add the route route-to-nva to the Route Table with destination 0.0.0.0/0, next hop type VirtualAppliance and next hop IP 10.10.10.4 (NVA fictional IP) using Add-AzRouteConfig and Set-AzRouteTable.
[PowerShell] Associate the Route Table ncarga-rt-compute to the subnet snet-compute of the network ncarga-vnet-compute using Set-AzVirtualNetworkSubnetConfig with the -RouteTable parameter.
Validation Criteria:
# Should return route-to-nva with NextHopType = VirtualAppliance, NextHopIpAddress = 10.10.10.4:
(Get-AzRouteTable -ResourceGroupName "ncarga-rg-network" -Name "ncarga-rt-compute").Routes |
Select-Object Name, AddressPrefix, NextHopType, NextHopIpAddress
# Should return the Route Table ID ncarga-rt-compute:
(Get-AzVirtualNetworkSubnetConfig -Name "snet-compute" -VirtualNetwork (Get-AzVirtualNetwork -Name "ncarga-vnet-compute" -ResourceGroupName "ncarga-rg-network")).RouteTable.Id
Step 58 β Troubleshoot network connectivity issuesβ
Context: After configuring the UDR in Step 57, the operations team reported that VM ncarga-vm-wms01 can no longer reach the storage account ncargatms001. The engineer needs to diagnose the cause using Network Watcher.
Tasks:
[PowerShell] Confirm that Network Watcher is active in the eastus region using Get-AzNetworkWatcher. If not, enable it with New-AzNetworkWatcher.
[Portal] Test the traffic flow from VM ncarga-vm-wms01 to the storage account ncargatms001 IP on port 443 at: Network Watcher β IP flow verify. Identify if traffic is allowed or blocked and which rule causes the blocking.
[Portal] Run a connectivity test at: Network Watcher β Connection troubleshoot. Test from VM ncarga-vm-wms01 to endpoint ncargatms001.blob.core.windows.net on port 443. Document the result and identified root cause.
Validation Criteria:
Network Watcher β IP flow verify: output showing Allow or Deny with the responsible rule name.Network Watcher β Connection troubleshoot: Reachable or Unreachable status with detailed hop-by-hop.
Step 59 β Create and configure NSGs and Application Security Groupsβ
Context: The security team approved a microsegmentation model using Application Security Groups (ASGs) to group VMs by function and apply NSG rules based on these groups, without depending on specific IPs.
Tasks:
[PowerShell] Create two Application Security Groups in resource group ncarga-rg-network using New-AzApplicationSecurityGroup:
ncarga-asg-wmsfor WMS system VMsncarga-asg-tmsfor TMS system VMs
[PowerShell] Associate VM ncarga-vm-wms01 NIC to ASG ncarga-asg-wms and NICs of ncarga-vm-tms01 and ncarga-vm-tms02 to ASG ncarga-asg-tms using Get-AzNetworkInterface and Set-AzNetworkInterface.
[PowerShell] Create NSG ncarga-nsg-compute and add a rule allowing traffic from port 8080 from ASG ncarga-asg-tms to ASG ncarga-asg-wms using Add-AzNetworkSecurityRuleConfig.
Validation Criteria:
# Should return ncarga-asg-wms and ncarga-asg-tms:
Get-AzApplicationSecurityGroup -ResourceGroupName "ncarga-rg-network" |
Select-Object Name, Location
# Should return rule with Access = Allow, port 8080:
(Get-AzNetworkSecurityGroup -ResourceGroupName "ncarga-rg-network" -Name "ncarga-nsg-compute").SecurityRules |
Select-Object Name, SourceApplicationSecurityGroups, DestinationApplicationSecurityGroups, DestinationPortRange, Access
Step 60 β Evaluate effective security rules in NSGsβ
Context: Before releasing TMS VMs to production, the security team requires a review of effective security rules applied to each NIC, including rules inherited from subnet and NIC NSGs.
Tasks:
[Portal] View effective rules of ncarga-vm-tms01 at: Virtual machines β ncarga-vm-tms01 β Networking β Network settings β Effective security rules. Document inbound and outbound rules, including source (subnet NSG vs NIC NSG).
[PowerShell] Get effective rules for VM ncarga-vm-tms01 NIC using Get-AzEffectiveNetworkSecurityGroup. Filter rules that block inbound traffic.
[PowerShell] Generate a report comparing effective rules of ncarga-vm-wms01 and ncarga-vm-tms01 with columns Name, Protocol, SourcePortRange, DestinationPortRange, Access, Priority and Direction. Export to ~/ncarga/nsg-effective-rules.csv.
Validation Criteria:
# Should return blocking rules with priority and ports:
Get-AzEffectiveNetworkSecurityGroup -NetworkInterfaceName <nic-tms01> -ResourceGroupName "ncarga-rg-vms" |
Select-Object -ExpandProperty EffectiveSecurityRules |
Where-Object { $_.Access -eq "Deny" -and $_.Direction -eq "Inbound" } |
Select-Object Name, Priority, DestinationPortRange
Step 61 β Implement Azure Bastionβ
Context: Project Anchor VMs do not have public IP. For secure administrative access without exposing RDP or SSH ports, the IT team will deploy Azure Bastion in the AzureBastionSubnet subnet already created in Step 54.
Azure Bastion Standard generates ~USD 0.19/h. Delete the resource after use during the lab.
Tasks:
[PowerShell] Create public IP ncarga-pip-bastion in resource group ncarga-rg-network, region brazilsouth, SKU Standard, allocation Static using New-AzPublicIpAddress.
[PowerShell] Create Azure Bastion ncarga-bastion associated with subnet AzureBastionSubnet of network ncarga-vnet-services with public IP ncarga-pip-bastion, SKU Standard, using New-AzBastion.
[Portal] Confirm that the Bastion connection option is available at: Virtual machines β ncarga-vm-wms01 β Connect β Bastion. No need to perform login.
Validation Criteria:
# Should return ProvisioningState = Succeeded, Sku = Standard:
Get-AzBastion -ResourceGroupName "ncarga-rg-network" -Name "ncarga-bastion" |
Select-Object Name, ProvisioningState, @{N='Sku';E={$_.Sku.Name}}
Step 62 β Configure service endpoints for PaaSβ
Context: For VMs in subnet snet-compute to access storage account ncargatms001 securely without exposing traffic to the internet, the network team will configure Storage Service Endpoints on the subnet.
Tasks:
[PowerShell] Add Service Endpoint Microsoft.Storage to subnet snet-compute of network ncarga-vnet-compute using Set-AzVirtualNetworkSubnetConfig with the -ServiceEndpoint parameter.
[PowerShell] Add a VNet rule to storage account ncargatms001 firewall allowing traffic from subnet snet-compute using Add-AzStorageAccountNetworkRule -VirtualNetworkResourceId.
[PowerShell] Confirm that the VNet rule was added with Get-AzStorageAccountNetworkRuleSet.
Validation Criteria:
# Should return line with snet-compute and Action = Allow:
(Get-AzStorageAccountNetworkRuleSet -ResourceGroupName "ncarga-rg-storage" -AccountName "ncargatms001").VirtualNetworkRules |
Select-Object VirtualNetworkResourceId, Action
# Should return Service = Microsoft.Storage:
(Get-AzVirtualNetworkSubnetConfig -Name "snet-compute" -VirtualNetwork (Get-AzVirtualNetwork -Name "ncarga-vnet-compute" -ResourceGroupName "ncarga-rg-network")).ServiceEndpoints |
Select-Object Service
Step 63 β Configure private endpoints for PaaSβ
Context: Storage account ncargataudit001 contains sensitive audit logs. The security team requires that access be made exclusively via private network, using Private Endpoint to eliminate any public path.
Tasks:
[PowerShell] Create Private Endpoint ncarga-pe-audit-storage in resource group ncarga-rg-network, region brazilsouth, connected to storage account ncargataudit001 with sub-resource blob. Use New-AzPrivateEndpoint pointing to subnet snet-storage of ncarga-vnet-services.
[PowerShell] Create Private DNS Zone privatelink.blob.core.windows.net in resource group ncarga-rg-network and link it to network ncarga-vnet-services using New-AzPrivateDnsZone and New-AzPrivateDnsVirtualNetworkLink.
[PowerShell] Create DNS Zone Group for Private Endpoint ncarga-pe-audit-storage using New-AzPrivateDnsZoneGroup.
Validation Criteria:
# Should return ProvisioningState = Succeeded:
Get-AzPrivateEndpoint -ResourceGroupName "ncarga-rg-network" -Name "ncarga-pe-audit-storage" |
Select-Object Name, ProvisioningState
# Should return the created zone:
Get-AzPrivateDnsZone -ResourceGroupName "ncarga-rg-network" -Name "privatelink.blob.core.windows.net" |
Select-Object Name
Step 64 β Configure Azure DNSβ
Context: The customer portal needs to be accessible via custom domain (portal.novacarga.com.br) instead of the App Service default URL. Azure DNS will be used to manage the company domain DNS records.
Tasks:
[PowerShell] Create public DNS Zone novacarga.com.br in resource group ncarga-rg-network using New-AzDnsZone. Get the assigned nameservers.
[PowerShell] Create a CNAME record in the DNS Zone:
| Parameter | Value |
|---|---|
| Name | portal |
| TTL | 3600 |
| Target | ncarga-webapp-portal.azurewebsites.net |
Use New-AzDnsRecordSet with type CNAME.
[PowerShell] Create a TXT record for domain verification with name asuid.portal. Get the value of customDomainVerificationId with:
(Get-AzWebApp -Name ncarga-webapp-portal -ResourceGroupName ncarga-rg-compute).CustomDomainVerificationId
Validation Criteria:
# Should return at least 2 records: portal (CNAME) and asuid.portal (TXT):
Get-AzDnsRecordSet -ZoneName "novacarga.com.br" -ResourceGroupName "ncarga-rg-network" |
Select-Object Name, RecordType, Ttl
# Should return 4 Azure nameservers:
Get-AzDnsZone -Name "novacarga.com.br" -ResourceGroupName "ncarga-rg-network" |
Select-Object Name, NameServers
Step 65 β Configure an internal load balancerβ
Context: VMs ncarga-vm-tms01 and ncarga-vm-tms02 need load balancing for the TMS API. An internal Load Balancer will be configured to distribute port 8080 requests between the two VMs without public exposure.
Tasks:
[PowerShell] Create internal Load Balancer ncarga-lb-tms in resource group ncarga-rg-network, region eastus, SKU Standard, with static private IP 10.10.1.100 in subnet snet-compute.
[PowerShell] Configure the Load Balancer with:
- Frontend IP:
10.10.1.100in subnetsnet-compute - Backend pool:
ncarga-lb-tms-backendincluding NICs ofncarga-vm-tms01andncarga-vm-tms02 - Health probe: TCP on port 8080, 15-second interval
- Load balancing rule: port 8080 front to 8080 backend, TCP protocol
[PowerShell] Confirm that the backend pool contains both VMs with Get-AzLoadBalancerBackendAddressPoolConfig.
Validation Criteria:
# Should return Sku = Standard, ProvisioningState = Succeeded:
Get-AzLoadBalancer -ResourceGroupName "ncarga-rg-network" -Name "ncarga-lb-tms" |
Select-Object Name, @{N='Sku';E={$_.Sku.Name}}, ProvisioningState
# Should return both private IPs of TMS VMs:
(Get-AzLoadBalancerBackendAddressPoolConfig -LoadBalancer (Get-AzLoadBalancer -Name "ncarga-lb-tms" -ResourceGroupName "ncarga-rg-network") -Name "ncarga-lb-tms-backend").BackendAddresses |
Select-Object IpAddress
Step 66 β Troubleshoot load balancing issuesβ
Context: After configuring the Load Balancer in Step 65, the operations team reported that the health probe is not marking VMs as healthy. The engineer needs to diagnose and resolve the issue.
Tasks:
[Portal] Add the Health Probe Status metric with Average aggregation at: Load balancers β ncarga-lb-tms β Metrics. Identify if VMs are being marked as 0 (unhealthy) or 1 (healthy).
[Portal] Review the connectivity diagram at: Load balancers β ncarga-lb-tms β Insights. Identify the component causing the health probe failure.
[PowerShell] Add an inbound rule to the NSG of subnet snet-compute allowing TCP traffic on port 8080 from service tag AzureLoadBalancer:
# Add rule to NSG protecting subnet snet-compute:
# Source: AzureLoadBalancer | Destination port: 8080 | Action: Allow
Validation Criteria:
# Should return rule with SourceAddressPrefix = AzureLoadBalancer, Access = Allow, port 8080:
Get-AzNetworkSecurityGroup -ResourceGroupName "ncarga-rg-network" -Name "ncarga-nsg-compute" |
Select-Object -ExpandProperty SecurityRules |
Where-Object { $_.DestinationPortRange -eq "8080" -and $_.Access -eq "Allow" } |
Select-Object Name, Priority, SourceAddressPrefix, Access
Domain 7 β Monitoringβ
Step 67 β Interpret metrics in Azure Monitorβ
Context: With all Project Anchor infrastructure provisioned, the operations team needs visibility into critical resource performance.
Tasks:
[Portal] Create a chart at: Monitor β Metrics. Select resource ncarga-vm-wms01 and add the metrics:
| Metric | Aggregation |
|---|---|
| Percentage CPU | Average |
| Available Memory Bytes | Average |
| Disk Read Operations/Sec | Sum |
Set time range as Last 24 hours and granularity of 5 minutes.
[Portal] Add storage account ncargatms001 to the same chart with metric Transactions and aggregation Sum.
[Portal] Save the chart as a pinned visualization to a new dashboard called ncarga-dashboard-ops.
Validation Criteria:
Monitor β Metrics: chart with at least 3 metrics from VMncarga-vm-wms01displayed without errors.- Dashboard
ncarga-dashboard-opsvisible atDashboard β Shared dashboards.
Step 68 β Configure log settings in Azure Monitorβ
Context: GDPR compliance requires that access and operation logs from all critical resources be stored centrally and auditably. A Log Analytics Workspace will be the central log repository.
Tasks:
[PowerShell] Create Log Analytics Workspace ncarga-law-prod in resource group ncarga-rg-compute, region eastus, with 90-day retention using New-AzOperationalInsightsWorkspace.
[PowerShell] Configure Diagnostic Settings of storage account ncargatms001 to send logs of categories StorageRead, StorageWrite and StorageDelete (sub-resource blobServices) to workspace ncarga-law-prod using Set-AzDiagnosticSetting.
[PowerShell] Configure the Diagnostic Settings for VM ncarga-vm-wms01 to send metrics and logs to the workspace ncarga-law-prod.
Validation Criteria:
# Should return Sku = PerGB2018, RetentionInDays = 90:
Get-AzOperationalInsightsWorkspace -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-law-prod" |
Select-Object Name, Sku, RetentionInDays
# Should return at least one diagnostic setting:
Get-AzDiagnosticSetting -ResourceId (Get-AzStorageAccount -Name "ncargatms001" -ResourceGroupName "ncarga-rg-storage").Id |
Select-Object Name
Step 69 β Query and analyze logs in Azure Monitorβ
Context: After the log collection configured in Step 68, the security team needs reports on access to storage ncargatms001 and VM status.
Tasks:
[Portal] Run the KQL query below in: Log Analytics workspaces β ncarga-law-prod β Logs. Modify the filter to the last 24 hours and note the count of operations by category:
StorageBlobLogs
| where TimeGenerated > ago(24h)
| summarize Count = count() by OperationName, StatusCode
| order by Count desc
[Portal] Run a second query listing the last 10 write operations on storage (OperationName containing "Write"), displaying TimeGenerated, CallerIpAddress, AuthenticationType and StatusCode.
[Portal] Save the first query with the name ncarga-query-storage-ops in the category NovaCarga.
Validation Criteria:
Log Analytics β ncarga-law-prod β Logs β Queries β NovaCarga: queryncarga-query-storage-opslisted and executable.- Query 1 result: table with columns
OperationName,StatusCode,Count. May return zero results if the storage received no traffic β this is acceptable, as long as the query executes without KQL syntax errors.
Step 70 β Configure alert rules, action groups and alert processing rulesβ
Context: The operations team needs to be proactively notified when VM ncarga-vm-wms01 CPU exceeds 85% for more than 5 minutes, and when storage account ncargatms001 returns HTTP 5xx errors.
Tasks:
[PowerShell] Create the Action Group ncarga-ag-ops in resource group ncarga-rg-compute with an email action to ana.ferreira@<tenant>.onmicrosoft.com using New-AzActionGroup.
[PowerShell] Create the metric alert rule for VM ncarga-vm-wms01:
| Parameter | Value |
|---|---|
| Name | ncarga-alert-cpu-wms01 |
| Metric | Percentage CPU |
| Operator | GreaterThan |
| Threshold | 85 |
| Evaluation window | 5 minutes |
| Action Group | ncarga-ag-ops |
Use New-AzMetricAlertRuleV2.
[Portal] Create an Alert Processing Rule to suppress all alerts from the subscription during weekends in: Monitor β Alerts β Alert processing rules β Create.
Validation Criteria:
# Should return Enabled = True, Threshold = 85:
Get-AzMetricAlertRuleV2 -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-alert-cpu-wms01" |
Select-Object Name, Enabled, @{N='Threshold';E={$_.Criteria.AllOf[0].Threshold}}
# Should return Enabled = True:
Get-AzActionGroup -ResourceGroupName "ncarga-rg-compute" -Name "ncarga-ag-ops" |
Select-Object GroupShortName, Enabled
Step 71 β Configure and interpret monitoring with Azure Monitor Insightsβ
Context: The operations team needs operational dashboards for VMs and networks. Azure Monitor Insights provides pre-built visualizations for the main Anchor Project resources.
Tasks:
[Portal] Enable VM Insights for ncarga-vm-wms01 in: Monitor β Virtual Machines. Install the Azure Monitor agent (AMA) if prompted and point to workspace ncarga-law-prod.
[Portal] After enabling VM Insights, navigate to the Performance tab and identify the three processes that consume the most CPU on VM ncarga-vm-wms01.
[Portal] Select VNet ncarga-vnet-compute in: Monitor β Networks β Network Insights. Review the Topology tab and confirm that subnets, NSGs and peerings are correctly represented.
Validation Criteria:
Monitor β Virtual Machines:ncarga-vm-wms01listed with monitoring status = Monitored. Performance tab available with CPU, Memory, Disk and Network charts.Monitor β Networks β Network Insights:ncarga-vnet-computeandncarga-vnet-servicesdisplayed with topology. Peering between the two VNets visible in the diagram.
Step 72 β Use Azure Network Watcher and Connection Monitorβ
Context: The network team needs continuous monitoring of connectivity between WMS and TMS VMs and storage account ncargatms001. Connection Monitor will provide alerts if connectivity between these endpoints fails.
Tasks:
[Portal] Create connection monitor ncarga-cm-wms-storage in: Network Watcher β Connection monitor
- Source: VM
ncarga-vm-wms01 - Destination: endpoint
ncargatms001.blob.core.windows.net, port 443 - Test frequency: 60 seconds
- Workspace:
ncarga-law-prod
[Portal] Add a second test group to the same Connection Monitor monitoring ncarga-vm-tms01 β ncarga-vm-wms01 on port 8080.
[Portal] Wait for at least one test cycle (1 minute) and review results in Connection monitor β Tests. Confirm status (Pass/Fail) and average latency for each test group.
Validation Criteria:
Network Watcher β Connection monitor β ncarga-cm-wms-storage β Test groups: at least two test groups with status (Pass or Fail) and latency values.Monitor β Logs (ncarga-law-prod): queryNWConnectionMonitorTestResult | where TimeGenerated > ago(1h)returns records after the first collection cycle.
Domain 8 β Backup and Disaster Recoveryβ
Step 73 β Create a Recovery Services Vaultβ
Context: The Anchor Project disaster recovery plan requires that VMs and Azure Files file share have automatic backup. The Recovery Services Vault will be the centralized vault for all backup policies.
Tasks:
[PowerShell] Create Recovery Services Vault ncarga-rsv-prod in resource group ncarga-rg-compute, region eastus, with GeoRedundant redundancy using New-AzRecoveryServicesVault.
[PowerShell] Configure the vault storage type with Set-AzRecoveryServicesBackupProperty -BackupStorageRedundancy GeoRedundant.
[PowerShell] Set the vault context for subsequent operations with Set-AzRecoveryServicesVaultContext.
Validation Criteria:
# Should return ProvisioningState = Succeeded, Location = eastus:
Get-AzRecoveryServicesVault -Name "ncarga-rsv-prod" -ResourceGroupName "ncarga-rg-compute" |
Select-Object Name, Location, ProvisioningState
# Should return GeoRedundant:
(Get-AzRecoveryServicesBackupProperty -Vault (Get-AzRecoveryServicesVault -Name "ncarga-rsv-prod" -ResourceGroupName "ncarga-rg-compute")).BackupStorageRedundancy
Step 74 β Create an Azure Backup Vaultβ
Context: In addition to the Recovery Services Vault, the Anchor Project requires an Azure Backup Vault to protect managed disks and blobs using the new native service backup policies.
Tasks:
[CLI] Create Azure Backup Vault ncarga-bkpvault-prod in resource group ncarga-rg-compute, region eastus, with GeoRedundant redundancy and immutability in Unlocked mode using az dataprotection backup-vault create.
[Portal] Confirm storage type and immutability status in: Backup vaults β ncarga-bkpvault-prod β Properties.
[Portal] Confirm in: Backup vaults β ncarga-bkpvault-prod β Backup policies that the vault was created without configured policies.
Validation Criteria:
# Should return provisioningState = Succeeded:
az dataprotection backup-vault show --vault-name ncarga-bkpvault-prod \
--resource-group ncarga-rg-compute \
--query "{name:name, storageSettings:properties.storageSettings, provisioningState:properties.provisioningState}"
Step 75 β Create and configure a backup policyβ
Context: The recovery SLA defines: daily VM backup with 30-day retention, weekly backup with 12-week retention and monthly backup with 12-month retention.
Tasks:
[PowerShell] Get the default VM policy from vault ncarga-rsv-prod using Get-AzRecoveryServicesBackupProtectionPolicy -WorkloadType AzureVM. Use it as a base to create a custom policy.
[PowerShell] Create policy ncarga-bkp-policy-vm in vault ncarga-rsv-prod with:
- Daily backup at 02:00 UTC
- Daily retention: 30 days
- Weekly retention: 12 weeks (every Monday)
- Monthly retention: 12 months (first day of the month)
Use New-AzRecoveryServicesBackupProtectionPolicy.
[PowerShell] Confirm creation with Get-AzRecoveryServicesBackupProtectionPolicy -Name ncarga-bkp-policy-vm.
Validation Criteria:
$policy = Get-AzRecoveryServicesBackupProtectionPolicy -Name "ncarga-bkp-policy-vm"
# Should return WorkloadType = AzureVM with ScheduleRunTimes containing 02:00 UTC:
$policy | Select-Object Name, WorkloadType, @{N='ScheduleRunTimes';E={$_.SchedulePolicy.ScheduleRunTimes}}
# Should return 30:
$policy.RetentionPolicy.DailySchedule.DurationCountInDays
Step 76 β Perform backup and restore operations with Azure Backupβ
Context: With the policy configured, the IT team needs to enable protection for VM ncarga-vm-wms01 and run the first on-demand backup to validate the process before automatic nightly backup.
Tasks:
[PowerShell] Enable backup protection for VM ncarga-vm-wms01 using policy ncarga-bkp-policy-vm in vault ncarga-rsv-prod with Enable-AzRecoveryServicesBackupProtection.
[PowerShell] Trigger an on-demand backup using Backup-AzRecoveryServicesBackupItem. Capture the returned JobId and monitor progress with Get-AzRecoveryServicesBackupJob -JobId <id>.
[Portal] After completion, confirm in: Recovery Services vaults β ncarga-rsv-prod β Backup items β Azure Virtual Machine. VM ncarga-vm-wms01 should appear with status Backup succeeded and at least one restore point available.
Validation Criteria:
# Should return Status = Completed, Operation = Backup:
Get-AzRecoveryServicesBackupJob -JobId <captured-job-id> |
Select-Object JobId, Status, Operation, Duration
# Should return LastBackupStatus = Completed:
Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -WorkloadType AzureVM |
Where-Object { $_.Name -like "*wms01*" } |
Select-Object Name, LastBackupStatus, LastBackupTime
Step 77 β Configure Azure Site Recovery for Azure resourcesβ
Context: The business continuity plan defines that VM ncarga-vm-tms01 should have active replication to the Brazil South region as secondary region. Azure Site Recovery will manage continuous replication to ensure 4-hour RTO.
Tasks:
[Portal] Configure replication in: Virtual machines β ncarga-vm-tms01 β Disaster recovery
| Parameter | Value |
|---|---|
| Target region | Brazil South |
| Target subscription | same subscription |
| Target resource group | ncarga-rg-vms-dr (created automatically) |
| Replication vault | ncarga-rsv-prod |
| Cache storage account | create new (Standard_LRS) |
[Portal] Monitor progress in: Recovery Services vaults β ncarga-rsv-prod β Replicated items.
[Portal] After initial synchronization, confirm in: Recovery Services vaults β ncarga-rsv-prod β Replicated items β ncarga-vm-tms01 that status is Protected and Replication health is Healthy.
Validation Criteria:
Recovery Services vaults β ncarga-rsv-prod β Replicated items: ncarga-vm-tms01 listed with:
- Replication health: Healthy
- Status: Protected
- Target region: Brazil South (brazilsouth)
Step 78 β Perform failover to secondary region with Site Recoveryβ
Context: The business continuity team has scheduled a quarterly disaster recovery drill. A test failover of VM ncarga-vm-tms01 to the brazilsouth region will be executed on an isolated network to validate the process without affecting production.
Tasks:
[Portal] Execute test failover in: Recovery Services vaults β ncarga-rsv-prod β Replicated items β ncarga-vm-tms01 β Test Failover
- Recovery point: Latest processed
- Target Azure network: Create new or select a test network in
brazilsouth
[Portal] Wait for completion and confirm that test VM ncarga-vm-tms01-test was created in the brazilsouth region in the DR resource group.
[Portal] After validating the test VM, execute cleanup in: Replicated items β ncarga-vm-tms01 β Cleanup test failover. Confirm that test resources were removed and status returned to Protected.
Validation Criteria:
- During failover: Status = Test failover completed in jobs blade.
- After cleanup: Status returns to Protected, Replication health = Healthy.
Resource groups β ncarga-rg-vms-dr: VMncarga-vm-tms01-testpresent during drill and removed after cleanup.
Step 79 β Configure and interpret backup reports and alertsβ
Context: The IT manager requires a weekly report on the status of all Anchor Project backups. This step configures backup reports and creates alerts for failed backups.
Tasks:
[Portal] Configure backup reports in: Recovery Services vaults β ncarga-rsv-prod β Backup reports. Point to workspace ncarga-law-prod by clicking Configure Diagnostic Settings.
[Portal] Review active backup alerts in: Backup center β Alerts. Confirm that vault ncarga-rsv-prod is being monitored.
[Portal] In: Backup center β Reporting, select vault ncarga-rsv-prod and workspace ncarga-law-prod. Review tabs Summary, Backup Items and Jobs. Confirm that backup of ncarga-vm-wms01 appears in reports.
Validation Criteria:
# Should return backup job records (may take up to 24h to appear):
Invoke-AzOperationalInsightsQuery -WorkspaceId (Get-AzOperationalInsightsWorkspace -Name "ncarga-law-prod" -ResourceGroupName "ncarga-rg-compute").CustomerId `
-Query "AddonAzureBackupJobs | take 5" |
Select-Object -ExpandProperty Results
# If empty: confirm that vault Diagnostic Setting is configured for ncarga-law-prod
Backup center β Reporting:ncarga-vm-wms01visible in Backup Items tab with status Backup succeeded.
Final Environment Validationβ
Upon completing all 79 steps, the Anchor Project environment should be composed of the following active and integrated resources:
| Category | Resources | Resource Group |
|---|---|---|
| Identity | 3 users, 2 groups, 1 guest, SSPR | Microsoft Entra ID |
| Governance | 2 policies, 2 locks, budget, management group | ncarga-rg-financeiro / ncarga-rg-network |
| Storage | ncargatest001, ncargatms001, ncargatfiles001, ncargataudit001 | ncarga-rg-storage |
| Compute | ncarga-vm-wms01 (D4s_v3), ncarga-vm-tms01, ncarga-vm-tms02, ncarga-vmss-tracker | ncarga-rg-vms |
| Containers | ncargatregistry001, ncarga-aci-rastreamento, ncarga-ca-rastreamento | ncarga-rg-compute |
| App Service | ncarga-webapp-portal (P1v3, slot staging) | ncarga-rg-compute |
| Network | ncarga-vnet-compute, ncarga-vnet-services, NSGs, Bastion, LB, DNS, UDR, Private Endpoints | ncarga-rg-network |
| Monitoring | ncarga-law-prod, alerts, Connection Monitor, VM Insights | ncarga-rg-compute |
| Backup and DR | ncarga-rsv-prod, ncarga-bkpvault-prod, Site Recovery (Brazil South) | ncarga-rg-compute |
Final validation query:
# Should return at least 35 distinct resources:
Get-AzResource | Where-Object { $_.ResourceGroupName -like "ncarga-*" } | Measure-Object
AZ-104 Lab β NovaCarga LogΓstica S.A. | Prefix: ncarga | Mode: PowerShell | 79 steps | 8 domains