Search
  • AmistadGroup

Azure - Blueprints Deployment

The document scope is to explain how to deploy in an automated way what I am thinking to be an Azure base subscription with all the resources needed for future growth. When I am saying all resources I am referring to a dedicated resource group for the virtual network, network security groups, and route table; and a resource group dedicated to infrastructure resources like virtual machines, private links, recovery vault, key vault, and storage accounts.

Azure blueprint is very well explained in this Microsoft link https://docs.microsoft.com/en-us/azure/governance/blueprints/overview

At this stage, we assume the fact that a new subscription is created, added to your management group, and a user-assigned managed identity is created based on this link https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-manage-ua-identity-portal

Azure Blueprints portal looks like this one:

We have two options: to create a new blueprint and for that, we need to choose Bluperiont definitions or to use an existing blueprint definition and for that, we need to choose Assigned blueprints.

At this stage, I will go for Blueprint definitions and create a new blueprint, a blank new blueprint

Blueprints are using artifacts and these are the artifacts that you can deploy using a blueprint


For this case only, we will use the Resource Group artifact.

To deploy a Route Table, I used this piece of code


{
      "type": "Microsoft.Network/routeTables",
      "apiVersion": "2019-11-01",
      "name": "[parameters('routeTables_RT_name')]",
      "location": "northeurope",
      "tags": {
        "Environment": "Production",
        "Service": "Route Table"
      },
      "properties": {
        "disableBgpRoutePropagation": false,
        "routes": [
          {
            "name": "Defaultroute",
            "properties": {
              "addressPrefix": "0.0.0.0/0",
              "nextHopType": "VirtualAppliance",
              "nextHopIpAddress": "192.168.180.1"
            }
          }
        ]
      }
    }

To deploy a Vnet with 3 different subnets, with custom DNS servers, DDOS disabled because is done a hub-spoke level, and peering back to a hub-spoke subscription, I used this piece of code


{
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2019-11-01",
      "name": "[parameters('virtualNetworks_Vnet_name')]",
      "location": "northeurope",
      "dependsOn": [
        "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_WEB_NSG_name'))]",
        "[resourceId('Microsoft.Network/routeTables', parameters('routeTables_RT_name'))]",
        "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_DATA_NSG_name'))]",
        "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_APP_NSG_name'))]"
      ],
      "tags": {
        "Environment": "Production",
        "Service": "Vnet"
      },
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[parameters('addressSpace_TIER_range')]"
          ]
        },
        "dhcpOptions": {
          "dnsServers": [
            "192.168.0.21",
            "192.168.0.22"            
          ]
        },
        "subnets": [
          {
            "name": "[parameters('WEB')]",
            "properties": {
              "addressPrefix": "[parameters('subnetaddressPrefix_WEB_range')]",
              "addressPrefixes": [],
              "networkSecurityGroup": {
                "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_WEB_NSG_name'))]"
              },
              "routeTable": {
                "id": "[resourceId('Microsoft.Network/routeTables', parameters('routeTables_RT_name'))]"
              },
              "serviceEndpoints": [],
              "delegations": [],
              "privateEndpointNetworkPolicies": "Enabled",
              "privateLinkServiceNetworkPolicies": "Enabled"
            }
          },
          {
            "name": "[parameters('DATA')]",
            "properties": {
              "addressPrefix": "[parameters('subnetaddressPrefix_DATA_range')]",
              "addressPrefixes": [],
              "networkSecurityGroup": {
                "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_DATA_NSG_name'))]"
              },
              "routeTable": {
                "id": "[resourceId('Microsoft.Network/routeTables', parameters('routeTables_RT_name'))]"
              },
              "serviceEndpoints": [],
              "delegations": [],
              "privateEndpointNetworkPolicies": "Enabled",
              "privateLinkServiceNetworkPolicies": "Enabled"
            }
          },
          {
            "name": "[parameters('APP')]",
            "properties": {
              "addressPrefix": "[parameters('subnetaddressPrefix_APP_range')]",
              "addressPrefixes": [],
              "networkSecurityGroup": {
                "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_APP_NSG_name'))]"
              },
              "routeTable": {
                "id": "[resourceId('Microsoft.Network/routeTables', parameters('routeTables_RT_name'))]"
              },
              "serviceEndpoints": [],
              "delegations": [],
              "privateEndpointNetworkPolicies": "Enabled",
              "privateLinkServiceNetworkPolicies": "Enabled"
            }
          }
        ],
        "virtualNetworkPeerings": [
          {
            "name": "[concat(parameters('virtualNetworks_Vnet_name'), '-PEER-hub-spoke-VNet')]",
            "properties": {
              "peeringState": "Connected",
              "remoteVirtualNetwork": {
                "id": "[parameters('virtualNetworks_VNet_NE_externalid')]"
              },
              "allowVirtualNetworkAccess": true,
              "allowForwardedTraffic": true,
              "allowGatewayTransit": false,
              "useRemoteGateways": true,
              "remoteAddressSpace": {
                "addressPrefixes": [
                  "10.10.2.0/23"
                ]
              }
            }
          }
        ],
        "enableDdosProtection": false,
        "enableVmProtection": false
      }
    }

To deploy a networks security group (NSG) with a DENY ALL rule,I used this piece of code


{
      "type": "Microsoft.Network/networkSecurityGroups",
      "apiVersion": "2019-11-01",
      "name": "[parameters('networkSecurityGroups_APP_NSG_name')]",
      "location": "northeurope",
      "tags": {
        "Environment": "Production",
        "Service": "NSG"
      },
      "properties": {
        "securityRules": [
          {
            "name": "Deny_All",
            "properties": {
              "protocol": "*",
              "sourcePortRange": "*",
              "destinationPortRange": "*",
              "sourceAddressPrefix": "*",
              "destinationAddressPrefix": "VirtualNetwork",
              "access": "Deny",
              "priority": 4000,
              "direction": "Inbound",
              "sourcePortRanges": [],
              "destinationPortRanges": [],
              "sourceAddressPrefixes": [],
              "destinationAddressPrefixes": []
            }
          },
        }

To deploy a Key Vault with full permissions I used this piece of code


    {
      "type": "Microsoft.KeyVault/vaults",
      "apiVersion": "2016-10-01",
      "name": "[parameters('vaults_KeyVault_name')]",
      "location": "northeurope",
      "properties": {
        "sku": {
          "family": "A",
          "name": "Standard"
        },
        "tenantId": "xxx",
        "accessPolicies": [
          {
            "tenantId": "xxx",
            "objectId": "yyy",
            "permissions": {
              "keys": [
                "Get",
                "List",
                "Update",
                "Create",
                "Import",
                "Delete",
                "Recover",
                "Backup",
                "Restore",
                "Decrypt",
                "Encrypt",
                "UnwrapKey",
                "WrapKey",
                "Verify",
                "Sign",
                "Purge"
              ],
              "secrets": [
                "Get",
                "List",
                "Set",
                "Delete",
                "Recover",
                "Backup",
                "Restore"
              ],
              "certificates": []
            }
          },
          {
            "tenantId": "xxx",
            "objectId": "yyy",
            "permissions": {
              "keys": [
                "Get",
                "List",
                "Update",
                "Create",
                "Import",
                "Delete",
                "Recover",
                "Backup",
                "Restore",
                "Decrypt",
                "Encrypt",
                "UnwrapKey",
                "WrapKey",
                "Verify",
                "Sign",
                "Purge"
              ],
              "secrets": [
                "Get",
                "List",
                "Set",
                "Delete",
                "Recover",
                "Backup",
                "Restore",
                "Purge"
              ],
              "certificates": [
                "Get",
                "List",
                "Update",
                "Create",
                "Import",
                "Delete",
                "Recover",
                "Backup",
                "Restore",
                "ManageContacts",
                "ManageIssuers",
                "GetIssuers",
                "ListIssuers",
                "SetIssuers",
                "DeleteIssuers",
                "Purge"
              ],
              "storage": []
            }
          }
        ],
        "enabledForDeployment": true,
        "enabledForDiskEncryption": true,
        "enabledForTemplateDeployment": true,
        "enableSoftDelete": true
      }
    }

To deploy a storage account to be used for virtual machine diagnostics, I used this piece of code:


    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2019-06-01",
      "name": "[parameters('storageAccounts_vmdiagnostics')]",
      "location": "northeurope",
      "sku": {
        "name": "Standard_RAGRS",
        "tier": "Standard"
      },
      "kind": "StorageV2",
      "properties": {
        "networkAcls": {
          "bypass": "AzureServices",
          "virtualNetworkRules": [],
          "ipRules": [],
          "defaultAction": "Allow"
        },
        "supportsHttpsTrafficOnly": true,
        "encryption": {
          "services": {
            "file": {
              "keyType": "Account",
              "enabled": true
            },
            "blob": {
              "keyType": "Account",
              "enabled": true
            }
          },
          "keySource": "Microsoft.Storage"
        },
        "accessTier": "Hot"
      }
    },
    {
      "type": "Microsoft.Storage/storageAccounts/blobServices",
      "apiVersion": "2019-06-01",
      "name": "[concat(parameters('storageAccounts_vmdiagnostics'), '/default')]",
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_vmdiagnostics'))]"
      ],
      "sku": {
        "name": "Standard_RAGRS",
        "tier": "Standard"
      },
      "properties": {
        "cors": {
          "corsRules": []
        },
        "deleteRetentionPolicy": {
          "enabled": false
        }
      }
    },
    {
      "type": "Microsoft.Storage/storageAccounts/fileServices",
      "apiVersion": "2019-06-01",
      "name": "[concat(parameters('storageAccounts_vmdiagnostics'), '/default')]",
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_vmdiagnostics'))]"
      ],
      "sku": {
        "name": "Standard_RAGRS",
        "tier": "Standard"
      },
      "properties": {
        "cors": {
          "corsRules": []
        }
      }
    }

When you completed your blueprint creation you need to save that under a name that best describes what this blueprint does and publish that blueprint.

The most important thing after the blueprint publishing is to assign that blueprint to a subscription and to see this message

Task completed.


Thank you!

AmistadGroup IT Team

(https://www.amistadgroup.ro/)

19 views0 comments

© 2020 Amistad Group S.R.L