Comment sécuriser son Azure Virtual WAN avec Azure Firewall et Azure Firewall Manager (preview)

Azure Firewall Manager (preview)

Introduction

Pour pouvoir suivre cet article sereinement, il faut avoir un minimum de connaissances en matière de SD-WAN/Azure virtaul WAN. L’une des dernières mises à jour de vWAN et qui rend l’outil encore plus intéressant, est la possibilité de déployer une instance d’Azure Firewall sur le Hub. Cette fonctionnalité est fournie avec un autre service, Azure Firewall Manager, sur lequel je voudrais me concentrer aujourd’hui.

Azure Firewall Manager a été publié très récemment, lors du dernier Ignite. Le service permet aux utilisateurs de déployer de manière centralisée des instances d’Azure Firewall sur différents vHubs, sur plusieurs régions et souscriptions. Une fois provisionnées, ces instances peuvent être gérées de manière centralisée en ce qui concerne les règles de pare-feu. Les règles peuvent désormais être déployées de manière hiérarchique, ce qui signifie que l’équipe informatique centrale (global admin) peut fournir une politique globale, en plus de laquelle les organisations locaux peuvent implémenter leurs propres politiques de règles plus spécifiques. Un seul niveau d’héritage est cependant autorisé.

Dans le format actuel, le service offre la possibilité de déployer des pare-feu sur des vHUB créés dans un Azure virtuel WAN. Firewall Manager propose également une gestion centralisée des itinéraires. Cette fonctionnalité est fantastique à mon avis – avec un seul commutateur, nous pouvons forcer le trafic via le pare-feu, sans avoir à créer des itinéraires définis par l’utilisateur.

Objectif de cet article

Dans cet article, nous allons voir comment déployer des vSecure HUB dans un environnement Azure WAN afin de tester les fonctionnalités d’Azure Firewall Manager. Pour cela, nous utiliserons Azure CLI, à ce jour, il n’est toujours pas possible de le faire en Powershell/Terraform.

Notre exemple portera sur les ressources suivantes :

  • 1 Azure Virtual WAN
  • 3 vHUB
    • un virtual HUB pour la region west-us
    • un virtual HUB pour la region east-us
    • un virtual HUB pour la region west-europe
  • 1 VPN Gateway (branch onpremise)
  • 4 Azure Firewall Policy (preview)
    • root-policy (global admin)
    • westus-region-policy (local admin)
    • eastus-region-policy (local admin)
    • westeurope-region-policy (local admin)

Let’s Go !

Pour avoir une image de l’infrastructure cible, voici un schéma récapitulatif.

Virtual Azure WAN

Commençons par créer le Azure Virtual WAN.

az group create --location eastus  --name demo-rg-vwan


# Virtual WAN
az extension add --name virtual-wan

az network vwan create --name demo-virtual-wan --resource-group demo-rg-vwan --branch-to-branch-traffic true --location eastus --type Standard  --vnet-to-vnet-traffic true

Azure Virtual HUB

Créez les Azure Virtual HUB.

# the west-us hub region
az network vhub create --address-prefix 10.100.0.0/16  --name demo-hub-westus  --resource-group demo-rg-vwan  --vwan demo-virtual-wan  --location westus  --sku  Standard

# the east-us hub region
az network vhub create --address-prefix 10.200.0.0/16  --name demo-hub-eastus  --resource-group demo-rg-vwan --vwan demo-virtual-wan  --location eastus  --sku  Standard

# the west-europe hub region
az network vhub create --address-prefix 10.255.0.0/16  --name demo-hub-westeurope  --resource-group demo-rg-vwan  -vwan demo-virtual-wan  --location westeurope --sku  Standard

Créez une Firewall-Policies et sécurisez les hub

Créez les Firewall-Policies.

# vSecure HUB policy

az extension add --name azure-firewall

az network firewall policy create --name fw-policy-root  --resource-group demo-rg-vwan   --location eastus    --threat-intel-mode Alert

az network firewall policy create --name fw-policy-westeurope   --resource-group demo-rg-vwan  --location eastus  --threat-intel-mode Alert  --base-policy fw-policy-root
                                                                              

az network firewall policy create --name fw-policy-westus  --resource-group demo-rg-vwan  --location eastus  --threat-intel-mode Alert --base-policy fw-policy-root
                                                                               

az network firewall policy create --name fw-policy-eastus  --resource-group demo-rg-vwan  --location eastus  --threat-intel-mode Alert --base-policy fw-policy-root

Connectez les Vnets/Branch

# VPN Gateway site-to-site (onpremise branch of east-us region)

az network vpn-gateway create --name demo-vpn-gateway   --resource-group demo-rg-vwan  --vhub demo-hub-eastus  --location eastus

az network vpn-site create --ip-address 137.117.35.59  --name demo-vpn-site  --virtual-wan demo-virtual-wan  --resource-group demo-rg-vwan --address-prefixes 10.5.0.0/16  --device-model firewall --device-vendor paloalto  --link-speed 20  --location eastus
                           
az network vpn-gateway connection create --gateway-name demo-vpn-gateway --name demo-vpn-gateway-connection --remote-vpn-site demo-vpn-site --resource-group demo-rg-vwan --connection-bandwidth 50 --protocol-type IKEv2 --shared-key ######################

# Virtual Hub to VNET connection (VNET Branch west us gerios)

az network vhub connection create --name  vnet-westus-prod-to-hub --remote-vnet "remote-vnet-id" --resource-group demo-rg-vwan --vhub-name  demo-hub-westus --internet-security true 

# Virtual Hub to VNET connection (VNET Branch west europe gerios)

az network vhub connection create --name  vnet-westeurope-prod-to-hub --remote-vnet "remote-vnet-id" --resource-group demo-rg-vwan  --vhub-name  demo-hub-westeurope --internet-security true --remote-vnet-transit   true --use-hub-vnet-gateways true

n’oubliez pas de configurer le tunnel IPSEC sur votre Appliance onpremise.

Creez vos Rules/Collections

# Policies

az network firewall policy rule-collection-group create --name rule-collection-westeurope --policy-name fw-policy-westeurope --priority 100 --resource-group demo-rg-vwan --location eastus

az network firewall policy rule-collection-group collection add-nat-collection --collection-priority 100 --name nat-collection --policy-name fw-policy-westeurope --resource-group demo-rg-vwan --rule-collection-group-name rule-collection-westeurope --action DNAT --destination-addresses 51.124.93.205 --destination-ports 22 --ip-protocols TCP --rule-name nat-ssh --source-addresses *  --translated-address 10.0.1.4  --translated-port 22 

az network firewall policy rule-collection-group collection add-filter-collection --collection-priority 200 --name net-collection --policy-name fw-policy-westeurope --resource-group demo-rg-vwan --rule-collection-group-name rule-collection-westeurope --action Allow --destination-ports *  --ip-protocols Any --protocols * --rule-name allowall --rule-type NetworkRule --source-addresses 10.0.0.0/16 --destination-addresses 10.0.0.0/16



az network firewall policy rule-collection-group create --name rule-collection-westus --policy-name fw-policy-westus --priority 100 --resource-group demo-rg-vwan --location eastus

az network firewall policy rule-collection-group collection add-nat-collection --collection-priority 100 --name nat-collection --policy-name fw-policy-westus --resource-group demo-rg-vwan --rule-collection-group-name rule-collection-westus --action DNAT --destination-addresses 13.83.64.91  --destination-ports 22 --ip-protocols TCP --rule-name nat-ssh --source-addresses *  --translated-address 10.0.0.4  --translated-port 22 

az network firewall policy rule-collection-group collection add-filter-collection --collection-priority 200 --name net-collection --policy-name fw-policy-westus --resource-group demo-rg-vwan --rule-collection-group-name rule-collection-westus --action Allow --destination-ports *  --ip-protocols Any --protocols * --rule-name allowall --rule-type NetworkRule --source-addresses 10.0.0.0/16 --destination-addresses 10.0.0.0/16
                                                                                                                        

az network firewall policy rule-collection-group create --name rule-collection-eastus --policy-name fw-policy-eastus --priority 100 --resource-group demo-rg-vwan --location eastus

az network firewall policy rule-collection-group collection add-filter-collection --collection-priority 200 --name net-collection --policy-name fw-policy-eastus --resource-group demo-rg-vwan --rule-collection-group-name rule-collection-eastus --action Allow --destination-ports *  --ip-protocols Any --protocols * --rule-name allowall --rule-type NetworkRule --source-addresses 10.0.0.0/8 --destination-addresses 10.0.0.0/8
 

Et enfin acheminer le trafic vers votre hub

Vous devez maintenant vous assurer que le trafic réseau est acheminé via votre vSecure Hub. Cette étape n’étant toujours pas disponible en Cli/Powershell/Terraform, on le fera directement sur le portail.

  1. depuis l’interface Firewall Manager, select Secured virtual hubs.
  2. Select the Hub.
  3. Under Settings, select Route settings.
  4. Under Internet trafficTraffic from Virtual Networks, select Send via Azure Firewall.
  5. Under Azure private trafficTraffic to Virtual Networks, select Send via Azure Firewall.
  6. Select Edit IP address prefix(es).
  7. Select Add an IP address prefix.
  8. Under Settings, select Connections.
  9. Select the spoke (VNETs/VPN site-site) connection, and then select Secure internet traffic and then select OK.

Conclusion

Je n’ai pas encore effectué de tests plus poussés, mais jusqu’à présent, je suis très satisfait de ce nouveau service. Une fois qu’il aura atteint la disponibilité générale, il pourrait rejoindre facilement notre Azure Virtual WAN pour former « Le » meilleure package d’outils pour le déploiement de réseaux de types Hub & Spoke natif Azure, et je vous laisse imaginez à quel point cette manière de faire facilitera la manipulation des pipelines CI / CD par rapport à notre façon de faire actuelle. 

Comment automatiser le déploiement des ressources Azure avec Terraform à l'aide des Pipelines Azure DevOps.

TERRAFORM

Terraform est un outil open-source développé par HashiCorp, et utilisé pour provisionner et gérer des infrastructures IT dans le Cloud. Écrit en Go et fonctionnant en mode Infrastructure as a Code (IAC), il permet d’administrer une infrastructure grâce à du code au lieu de procéder à un ensemble d’opérations manuelles.

La force de Terraform est de reposer sur un langage de description d’infrastructure simple et lisible, on parle ici de HCL. L’approche IAC de Terraform permet de gérer le versioning d’une infrastructure en lui ajoutant ou retirant des composants.

Objectif

Dans cet article, nous allons voir :

  1. Comment définir une stack Terraform simple
  2. Comment utiliser conjointement Terraform et Azure DevOps dans l’optique de déployer l’infrastructure Azure, de manière automatique et continue.

Initialisation du projet

Voici la structure de fichier que nous allons adopter :

|– src\
|– terraform\
|– README.md

|– src\ will contain the sources of the Ansible Config,
|– terraform\ will contain all the deployment files.

1- Azure service principal

Rendons-nous dans Azure Active Directory et allons dans la partie App registrations.

  • Connectez-vous à votre compte Azure sur https://portal.azure.com
  • Cliquez sur le bouton Cloud Shell pour lancer le Cloud Shell.
  • La commande ci-dessous créera un principal de service avec le nom « SPName ». Remplacez la valeur et exécutez la commande dans le cloud shell.
az ad sp create-for-rbac --name SPName
  • À l’issu de cette commande, Azure CLI retournera un block JSON contenant les informations nécessaires a l’authentification du SP (client-id, client-secret)
abd###@Azure:~$ az ad sp create-for-rbac --name SPName
Changing "SPName" to a valid URI of "http://SPName", which is the required format used for service principal names
Creating a role assignment under the scope of "/subscriptions/##########-c1b3-####-8b7a-####9578ebf0"
  Retrying role assignment creation: 1/36
  Retrying role assignment creation: 2/36
  Retrying role assignment creation: 3/36
{
  "appId": "########-4611-4c09-9728-6ec9284314de",
  "displayName": "SPName",
  "name": "http://SPName",
  "password": "########",
  "tenant": "########-d76d-45cf-a7d2-ae98f73067ee"
}
  • Complétez le formulaire. Cliquez sur Vérifier la connexion pour vous assurer que les valeurs fonctionnent comme prévu. Cliquez sur OK une fois vérifié. Vous pourrez désormais référencer cette connexion à partir des tasks du pipeline.

2- TERRAFORM / INFRASTRUCTURE

|– src\
|– terraform\
____|– main.tf
____|– outputs.tf
____|– provider.tf
____|– variables.tf
____|– variables.tfvars
|– README.md

MAIN.tf file

data "azurerm_client_config" "current" {
}

locals {
  resource_group_name = "rg-${var.env}"

  tags = {
    env = "${var.env}"
  }
}

# ======================================================================================
# Resource Group
# ======================================================================================

resource "azurerm_resource_group" "resource_group" {
  location = "${var.location}"
  name     = "${var.env}-rg"
  tags     = "${local.tags}"
}

# ======================================================================================
# KeyVault
# ======================================================================================

resource "azurerm_key_vault" "key_vault" {
  name                        = "${var.env}-keyvault"
  location                    = "${azurerm_resource_group.app_resource_group.location}"
  resource_group_name         = "${azurerm_resource_group.app_resource_group.name}"
  tenant_id                   = "${data.azurerm_client_config.current.tenant_id}"
  enabled_for_disk_encryption = true

  sku {
    name = "standard"
  }

  access_policy {
    tenant_id = "${data.azurerm_client_config.current.tenant_id}"
    object_id = "${data.azurerm_client_config.current.object_id}"

    secret_permissions = [
      "get",
      "list",
      "set",
      "delete"
    ]
  }

  tags = "${local.tags}"
}

# ======================================================================================
# Network
# ======================================================================================

resource "azurerm_virtual_network" "vnet" {
  name                = "${var.vnet-name}"
  address_space       = "${var.address_space}"
  dns_servers         = [
           "192.168.0.1",
           "168.168.25.1",
        ]
  location            = "${azurerm_resource_group.resource_group.location}"
  resource_group_name = "${azurerm_resource_group.resource_group.name}"

  tags     = "${local.tags}"
}

resource "azurerm_subnet" "subnet" {
  name                 = "${var.subnet-name}"
  resource_group_name  = "${azurerm_resource_group.resource_group.name}"
  virtual_network_name = "${azurerm_virtual_network.vnet.name}"
  address_prefix       = "${var.address_prefix}"
  tags     = "${local.tags}"
}

resource "azurerm_network_interface" "vm-network-interface" {
  name                = "${var.vm-name}"
  location            = "${azurerm_resource_group.resource_group.location}"
  resource_group_name = "${azurerm_resource_group.resource_group.name}"
  
  ip_configuration {
    name                          = "vm-ipconfig"
    subnet_id                     = "${azurerm_subnet.subnet.id}"
    private_ip_address_allocation = "Dynamic"
  }
}
# ======================================================================================
# VM
# ======================================================================================

resource "azurerm_virtual_machine" "virtual-machine" {
  name                  = "${var.vm-name}"
  location              = "${azurerm_resource_group.resource_group.location}"
  resource_group_name   = "${azurerm_resource_group.resource_group.name}"
  network_interface_ids = ["${azurerm_network_interface.vm-network-interface.id}"]

  vm_size               = "DS3V2"

  storage_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2016-Datacenter"
    version   = "latest"
  }
  storage_os_disk {
    name              = "vm-os-disk"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
    
  }

  os_profile {
    computer_name  = "${var.computer-name}"
    admin_username = "${var.AdminUsername}"
    admin_password = "${var.AdminPassword}"
  }

}

PROVIDER.TF file

provider "azurerm" {
  version = "1.44.0"
}

terraform {
  required_version = "0.11.21"
  backend "azurerm" {
    storage_account_name = "shared$$_application_$$tfsa"
    container_name       = "terraform"
    key                  = "terraform-$$_environment_$$.tfstate"
    access_key           = "$$_tf_storage_account_key_$$"
  }
}

VARIABLES.TF file

data "azurerm_client_config" "current" {
}

provider "azurerm" {
    version = "=1.44.0"
    subscription_id  = "${data.azurerm_client_config.current.subscription_id}"               
    client_id        = "${data.azurerm_client_config.current.client_id}"                  
    tenant_id        = "${data.azurerm_client_config.current.tenant_id}"
    client_secret    = "$$_client_secret_$$"                 
    }

variable "env" {
  type = "string"
}
variable "location" {
  type = "string"
}
variable "address_space" {
  type = "string"
}
variable "subnet-name" {
  type = "string"
}
variable "address_prefix" {
  type = "string"
}

VARIABLES.TFVARS file

env = "$$_env_$$"
location = "$$_location_$$"
address_space = "$$_0.0.0.0/0_$$"
subnet-name = "$$_subnet-name_$$"
address_prefix = "$$_0.0.0.0/24_$$"

3- PIPELINE

Prérequis

Un compte GitHub, où vous pouvez gérer vos repository. Si vous n’en avez pas, vous pouvez créer un gratuitement.

Une organisation Azure DevOps. Si vous n’en avez pas, vous pouvez en créer une gratuitement. (Une organisation Azure DevOps est différente de votre organisation GitHub. Par best-practices, donnez-leur le même nom)

Commençons par créer notre premier pipeline !

1- Azure DevOps – BUILD

Créons un nouveau Build Pipeline, puis cliquer sur Use the visual designer pour avoir le mode visuel.

Pour ce lab, nous utiliserons la branche master.

commencer par un Empty job

Ensuite, ajoutez Publish Artifact. Cette étape est utilisée pour incorporer les fichiers Terraform dans l’artifact.

Ensuite, spécifiez le dossier ou le chemin du fichier à publier. Il peut s’agir d’un full path ou d’un chemin relatif à la racine du repository.

Enfin, procédons au lancement de notre première build. Si tout se passe bien, nous obtenons l’artifact suivant :

2- Azure DevOps – RELEASE

Créons maintenant un nouveau Release Pipeline, pour ce faire, nous allons commencer à partir d’un modèle de travail vide Empty job template.

Renommons la première étape DEV.

Pour utiliser Terraform, nous avons besoin de :

  1. créer son backend sur Azure Storage (Blob),
  2. récupérer la Key de ce Storage et de l’injecter dans les variables pour pouvoir écrire/lire dans le Blob.

Première étape, ajoutons une étape de type Azure CLI pour la création du backend :

az group create --location $(location) --name "rg-$(env)-tfstate" 

az storage account create --name "sa$(env)tfstate$(location)" --resource-group "rg-$(env)-tfstate" --location $(location) --sku Standard_LRS  --tags 

az storage container create --name "terraform" --account-name "sa$(env)tfstate$(location)"

Next, add a second job Azure Powershell to get the storage account access_key

$key = (Get-AzStorageAccountKey -ResourceGroup "rg-$(env)-tfstate" -Name "sa$(env)tfstate$(location)").Value[0]

Write-Host "##vso[task.setvariable variable=tf_storage_account_key]$key"

The following two steps allow you to replace the tokens ($$_value_$$) present in the Terraform files.

Ensuite, ajoutons les tasks terraform:

  • install terrafrom ()
  • init
  • validate
  • plan
  • apply

Add Pipiline variables

Link a KeyVault to your DevOps pipeline project

prochains articles :

  1. Configurer une ressource (AD serveur) a l’aide d’Ansible-DevOps en one shot
  2. Configurer une ressource (AD serveur) a l’aide du DSC-DevOps en one shot