28 C
Dubai
Saturday, April 26, 2025
Home Blog Page 17

Azure Hub and Spoke Network using reusable Terraform modules

We will deploy the resources below using Terraform reusable modules utilizing the Azure landing zone concept, part of the Cloud Adoption Framework (CAF). In this setup, we are talking about only infra resources; if you are new to terraform, the same concept has been explained using the Azure Portal; I have spoken about Azure Management Groups and Subscription Planning in this link – Azure Management Groups and Subscriptions Design

Azure landing zone design that accounts for scale, security governance, networking, and identity, which enables seamless application migration, modernization, and innovation at the enterprise scale in Azure. This approach considers all platform resources like infrastructure (Iaas) or platform as a service.

Benefits of Azure Landing Zones –

  • Good Governance ( Like you can place a policy in the overall environment that no internet-exposing storage accounts can be provisioned)
  • Security (Improved Security controls, Network segmentation, Identity management, Service Principals, Managed Identities)
  • Scalability (Multi Datacenter or Improving the design with Virtual WAN should be seamless)
  • Cost Savings (Segregated billing with subscriptions – Overall Control or like can apply Hybrid benefit using policies)


Resources Provisioned –

1.  Virtual Networks (Hub – 10.50.0.0/16 – Spoke – 10.51.0.0/16)
2. VPN Gateway (10.50.1.0/24)  – Not Provisioned by Default
3. Azure Firewall (10.50.2.0/24)
4. Application Gateway (10.50.3.0/24) – Not Provisioned by Default
5.  Azure Bastion (10.50.4.0/24)
6.  Jump Box (Windows 11) (10.50.5.0/24)
7.  Windows Server 2019 Web Server (10.51.1.0/24)
8.  Linux RHEL Server (10.51.2.0/24)
9.  Public IP Addresses
10. Recovery Services Vault
11. Azure Key Vault – Not Provisioned by Default
12. Route Tables
13. Azure Firewall Policies

Modules are convenient to place into folders and reuse resource configurations with Terraform for multiple deployments.
Also, changing/upgrading specific resource configurations becomes easier.

Git Hub Repo link –

azure365pro/azure-hub-spoke-terraform (github.com)

Needed Resources –

  • Terraform’s latest version is installed.
terraform -version
  • az CLI is installed / az login is completed
az login
  • Git is installed to clone the repository

Let’s clone the repository

git clone "https://github.com/azure365pro/azure-hub-spoke-terraform"

Get inside the repo

cd .\azure-hub-spoke-terraform\

Run Terraform init to create a local tfstate

terraform init

Make sure you are running on the right subscription. If you have access to multiple subscriptions

terraform plan

Now terraform apply command is used to create the resources.

terraform apply

Now terraform destroy command is used to clean up the resources.

terraform destroy

Running the same with Azure DevOps Releases with Muti Stage Approvals

We utilize stages, triggers and approvers, and deployment options in release pipelines.

Verify Stage with run init/plan

Prod Stage with run init/plan / apply

Application Settings in Azure App Service and Static Web Apps

Utilizing Connection Strings in PHP/Nodejs/Next Js for App Service – The source code is Deployed in UAT and Production; both have different connection strings, for example. So that pipeline is deployed smoothly without any manual changes utilizing DevOps variables. Let’s take an example of using the same codebase and applying it on UAT and Prod. My UAT will apply UAT DB Connection String, and Production will apply the Production Connection string for the same Codebase.

As you can see, I am adding this MYSQLCONNSTR_ suffix for my connection string as its MYSQL; you can update the suffix accordingly. Application settings don’t need any suffixes. Also, you can retrieve secrets from the key vault to run them in the App service without exposing them.

At runtime, connection strings are available as environment variables, prefixed with the following connection types:

  • SQLServer: SQLCONNSTR_
  • MySQL: MYSQLCONNSTR_
  • SQLAzure: SQLAZURECONNSTR_
  • Custom: CUSTOMCONNSTR_
  • PostgreSQL: POSTGRESQLCONNSTR_

For Retrieving from Key Vault, you need to specific the URI, and it will retrieve the latest version if the below format is used.

@Microsoft.KeyVault(SecretUri=https://az-az-pr-ause-kv.vault.azure.net/secrets/accesstoken/)



Utilizing Application Settings inside JSON in Azure Static Web Apps

To Retrieve from Azure Key Vault –

@Microsoft.KeyVault(SecretUri=https://az-az-pr-ause-kv.vault.azure.net/secrets/accesstoken/)

You can see Key vault Reference has been added.

System Assigned Identity is Turned On. To talk with key vault

Key Vault Reference

So that secret is not exposed even to the App Service Administrator for example.

Next Js Build Error fetch failed with undici

Node Js Build Error fetch failed with undici – Run Node Js 18.0 – 18.x minor versions cause this error. (Bug)

npm install

npm run dev

npm run build

C:\Scripts\repo\azure365pro-Guide>npm install

up to date, audited 707 packages in 4s

97 packages are looking for funding
  run `npm fund` for details

8 vulnerabilities (1 moderate, 3 high, 4 critical)

To address all issues, run:
  npm audit fix

Run `npm audit` for details.
npm notice
npm notice New major version of npm available! 8.19.2 -> 9.2.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v9.2.0
npm notice Run npm install -g npm@9.2.0 to update!
npm notice

C:\Scripts\repo\azure365pro-Guide>npm run dev

> dev
> next dev

ready - started server on 0.0.0.0:3000, url: http://localhost:3000
event - compiled client and server successfully in 869 ms (228 modules)
Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db

Why you should do it regularly:
https://github.com/browserslist/browserslist#browsers-data-updating
Terminate batch job (Y/N)? Y

C:\Scripts\repo\azure365pro-Guide>npm run build

> build
> next build

Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db

Why you should do it regularly:
https://github.com/browserslist/browserslist#browsers-data-updating
info  - Checking validity of types

./pages/buscar.js
92:7  Warning: React Hook useEffect has a missing dependency: 'fetchFilterOptions'. Either include it or remove the dependency array.  react-hooks/exhaustive-deps

./pages/colegio/[cid].js
261:65  Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images.  jsx-a11y/alt-text
278:33  Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images.  jsx-a11y/alt-text
294:60  Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images.  jsx-a11y/alt-text
318:25  Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images.  jsx-a11y/alt-text
323:25  Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images.  jsx-a11y/alt-text
328:25  Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images.  jsx-a11y/alt-text
336:25  Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images.  jsx-a11y/alt-text

./components/SearchInput.js
33:7  Warning: React Hook useEffect has a missing dependency: 'fetchFilterOptions'. Either include it or remove the dependency array.  react-hooks/exhaustive-deps

info  - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rules
Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db

Why you should do it regularly:
https://github.com/browserslist/browserslist#browsers-data-updating
info  - Creating an optimized production build
Failed to compile.

./public/images/banner.jpg
TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11118:11)

Import trace for requested module:
./pages/index.js

./public/images/condiciones.jpg
TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11118:11)

Import trace for requested module:
./pages/condiciones.js

./public/images/conoce.jpg
TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11118:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Import trace for requested module:
./pages/index.js

./public/images/graduation.jpg
TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11118:11)

Import trace for requested module:
./pages/buscar.js


> Build failed because of webpack errors

C:\Scripts\repo\azure365pro-Guide>

Single Sign-on using Azure AD with Static Web Apps

Single Sign-on using Azure AD with Static Web Apps, let’s create a Simple Azure AD Page, Enable Single Sign-on Using Azure AD.
Uploaded the same javascript below the GitHub repo.

Sign in, Redirects to Microsoft Login, and Logout Kills all the session.

GitHub Repo Reference – azure365pro/AAD-StaticWebApp: Simple Login Logout Page using Azure AD in Static Web App (github.com)

Let’s create an Azure Static Web App, Deployment source is GitHub.

Choose Organization / Repo / Branch / Build presets to Custom

Now the site is loaded using GitHub repo

Now lets create an enterprise application for Single Sign on

Assign users for enabling sso

Copy AZURE_CLIENT_ID

Add a Variable for the same

Copy AZURE_CLIENT_SECRET

Add a Variable for the same – Choose SAVE

Modify staticwebapp.config.json based on your environment, Maybe you can fork it and do a simple lab.

The appropriate tenant ID is updated in the JSON file.

App User.Read Permissions

Grant Admin Consent

Redirect URIs based on your URL Add /.auth/login/aad/callback
https://zealous-grass-0ea7c0c03.2.azurestaticapps.net/.auth/login/aad/callback

Choose Web

Based on my URL – Changing the login route to Authenticated directory.

https://zealous-grass-0ea7c0c03.2.azurestaticapps.net/authenticated/

As soon as you update any files – you can see GitHub Actions takes places to deploy

Update Index.js on Sign in Button action

https://zealous-grass-0ea7c0c03.2.azurestaticapps.net/authenticated/

Now after login

Deploy Next.js App on Azure App Service with Azure DevOps Pipelines

In this requirement. We are using CI / CD from the GitHub repository and creating an artifact and Deploying Next Js on Azure App Service, which is using “Strapi – Open source Node.js Headless CMS” from an Azure App Service using Azure DevOps Releases. We are using staging slots, and upon Approval, it will deploy to the production slot.

Good to know – CI/CD are Continuous Integration, Continuous Delivery, and Continuous Deployment

Pipelines are integrated with GitHub Repo for CI / CD and are deployed to UAT (Azure App Service Staging Slot ), where they can be tested. If it gets approved (Approval Gates), After testing, it will be deployed to the Production Slot in the same App Service. Otherwise, the change can be rejected.

Ran the node js locally using [ npm run dev / npm run build ], which went through successfully.


A similar article for CI / CD is done for Azure App Service using Azure DevOps.

Azure DevOps Pipelines for App Service with GitHub – Azure365Pro.com
Azure DevOps Pipelines for Static Web Apps with GitHub – Azure365Pro.com

As you see below, we are using a Git hub source repository. First Deploys to a Standard UAT (Azure App Service Staging Slot ). If an approver approves changes, It’s deployed to a Production Azure App Service.

Now you can see the releases happening on UAT and Production environments without any manual steps. Let’s see how to implement the same.

Create New Pipeline – Choose Github (YAML) as I use GitHub in my case

Choosing Node.js Express Web App on Linux on Azure

Using below YAML – azure-pipelines.yml

# Node.js Express Web App to Linux on Azure
# Build a Node.js Express app and deploy it to Azure as a Linux web app.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript

trigger:
- main

variables:

  # Azure Resource Manager connection created during pipeline creation
  azureSubscription: 'd4200000-0000-0000-0000-9bb00007d505'

  # Web app name
  webAppName: 'az-az365pro-pr-fc-web-rg'

  # Environment name
  environmentName: 'az-az365pro-pr-fc-web-rg'

  # Agent VM image name
  vmImageName: 'ubuntu-latest'

stages:
- stage: Build
  displayName: Build stage
  jobs:
  - job: Build
    displayName: Build
    pool:
      vmImage: $(vmImageName)

    steps:
    - task: NodeTool@0
      inputs:
        versionSpec: '18.x'
      displayName: 'Install Node.js'

    - script: |
        npm install
        npm run build --if-present
#       npm run test --if-present
      displayName: 'npm install, build and test'

    - task: ArchiveFiles@2
      displayName: 'Archive files'
      inputs:
        rootFolderOrFile: '$(System.DefaultWorkingDirectory)'
        includeRootFolder: false
        archiveType: zip
        archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
        replaceExistingArchive: true

    - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
      artifact: drop

Having two files in my repo

Added ecosystem.config.js. We need to start this separately

  module.exports = {
  apps: [
    {
      name: "az-az365pro-web",
      script: "./node_modules/next/dist/bin/next",
      args: "start -p " + (process.env.PORT || 3000),
      watch: false,
      autorestart: true,
    },
  ],
  };

if bin location is in different place

ecosystem.config.js.

  module.exports = {
  apps: [
    {
      name: "az-az365pro-web",
      script: "./node_modules/.bin/next",
      args: "start -p " + (process.env.PORT || 3000),
      watch: false,
      autorestart: true,
    },
  ],
  };

As you can see below, running this store my build to Azure Artifact where Azure Releases can use them.

Now as by build is released with the zip sent to my drop location
Now my source in releases is artifact

The startup command set to

pm2 start /home/site/wwwroot/ecosystem.config.js --no-daemon



if pm2 start command doesn’t exist – build will fail

root@fff533200d57:/home/site/wwwroot# npm run dev
npm info using npm@9.6.4
npm info using node@v18.16.1

> fulcrum-dashboard@0.1.0 dev
> next dev

node:internal/modules/cjs/loader:1080
throw err;
^

Error: Cannot find module ‘../build/output/log’
Require stack:
– /home/site/wwwroot/node_modules/.bin/next
at Module._resolveFilename (node:internal/modules/cjs/loader:1077:15)
at Module._load (node:internal/modules/cjs/loader:922:27)
at Module.require (node:internal/modules/cjs/loader:1143:19)
at require (node:internal/modules/cjs/helpers:110:18)
at Object. (/home/site/wwwroot/node_modules/.bin/next:6:54)
at Module._compile (node:internal/modules/cjs/loader:1256:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
at Module.load (node:internal/modules/cjs/loader:1119:32)
at Module._load (node:internal/modules/cjs/loader:960:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) {
code: ‘MODULE_NOT_FOUND’,
requireStack: [ ‘/home/site/wwwroot/node_modules/.bin/next’ ]
}

.

Staging is set to a Staging slot.

Staging slot is created for use – Add Slot – Staging

In my next stage Production Slot is chosen with the same settings

Now my App Service URLs are ready with below

Staging – (Upon Approval, Goes to Prod)
https://azure365pro-statging.azurewebsites.net/en-US
Production –
https://azure365pro.azurewebsites.net/en-US

Continous Deployment Trigger is enabled so that UAT is pushing on every new build.

Azure DevOps Pipelines for Static Web Apps with GitHub

In this requirement. We are using CI / CD from the GitHub repository and Deploying Next Js Static pages which are using “Strapi – Open source Node.js Headless CMS” from an Azure App Service. We are not using staging slots in this to keep the UAT and Prod completely independent

Good to know – CI/CD are Continuous Integration, Continuous Delivery, and Continuous Deployment

Pipelines are integrated with GitHub Repo for CI / CD and are deployed to UAT (Azure Static Web App ) where they can be tested, if it gets approved (Approval Gates) after testing it will be deployed to Production. Otherwise, the change can be rejected.

Ran the node js locally using [ npm run dev / npm run build ] which went through successfully.

Linking a similar article for CI / CD is done for Azure App Service using Azure DevOps
Azure DevOps Pipelines for App Service with GitHub – Azure365Pro.com

As you see below we are using a Git hub source repository. First Deploys to a Standard UAT Azure Static Web App if changes are approved by an approver, It’s deployed to a Production Azure Static Web App.

Please note: Azure DevOps integration using Deployment tokens currently supports only on the Standard version of Azure static Web Apps and not in the free version of Azure Static Web Apps.

Now you can see the releases happening on UAT and Production environments without any manual steps. Let’s see how to implement the same.

Create New Release Pipeline

Utilizing GitHub Repo Source Type

To Keep the Git hub repo more secure – We will use Personal Tokens in this Scenario as the account hold many repos belonging to different projects. (Most of them can skip this step – It’s only for companies who want to host many repositories from different customers)

Use the personal token generated from Github Fine-Grained Tokens – Which has access to the specific Repo.

Provide All Repository Permissions

Create a Stage using ubuntu-latest

Create another task – Static Web App – Deploy Azure Static Web App, which is currently in preview.

App Location set to “/”

Now Get the deployment token from the Azure Static Web App

Enter the variable value to be set on the Azure Static Web Apps API token

Create variables for UAT and Prod to use at different stages

Name – Variable Name
Value – Deployment Token Value
and press the lock button to save it as a secret

Now if you deploy it. It generates its yml and deploys it to the appropriate static web app using the deployment token

Deploys to UAT

Deploys to Prod

If you see the stages – UAT and Prod succeeded.

Enabled Continous Deployment Trigger in this specific scenario. On Each commit/push to the repo it Auto Deploys to UAT.

× How can I help you?