Ejemplo n.º 1
0
    def _add_vm(self, cfg, r, vnet_in_deployment):
        res = cfg["resources"][r]
        rtype = res["type"]
        rsize = res["vm_type"]
        rimage = res["image"]
        ros = rimage.split(':')
        rinstances = res.get("instances", 1)
        rpip = res.get("public_ip", False)
        rdns = res.get("dns_name", None)
        rnsgallow = res.get("nsg_allow", None)
        rppg = res.get("proximity_placement_group", False)
        rppgname = cfg.get("proximity_placement_group_name", None)
        raz = res.get("availability_zones", None)
        rsubnet = res["subnet"]
        ran = res.get("accelerated_networking", False)
        rlowpri = res.get("low_priority", False)
        rosdisksize = res.get("os_disk_size", None)
        rosstoragesku = res.get("os_storage_sku", "Premium_LRS")
        rdatadisks = res.get("data_disks", [])
        rstoragesku = res.get("storage_sku", "Premium_LRS")
        rstoragecache = res.get("storage_cache", "ReadWrite")
        rtags = res.get("resource_tags", {})
        rmanagedidentity = res.get("managed_identity", None)
        loc = cfg["location"]
        ravset = res.get("availability_set")
        customdata = res.get("custom_data", None)
        adminuser = cfg["admin_user"]
        rrg = cfg["resource_group"]
        vnetname = cfg["vnet"]["name"]
        vnetrg = cfg["vnet"].get("resource_group", rrg)
        if vnet_in_deployment:
            rsubnetid = "[resourceId('Microsoft.Network/virtualNetworks/subnets', '{}', '{}')]".format(
                vnetname, rsubnet)
        else:
            rsubnetid = "[resourceId('{}', 'Microsoft.Network/virtualNetworks/subnets', '{}', '{}')]".format(
                vnetrg, vnetname, rsubnet)
        rpassword = res.get("password", "<no-password>")
        with open(adminuser + "_id_rsa.pub") as f:
            sshkey = f.read().strip()

        if ravset and ravset not in self.avsets:
            arm_avset = {
                "name": ravset,
                "type": "Microsoft.Compute/availabilitySets",
                "apiVersion": "2018-10-01",
                "location": loc,
                "sku": {
                    "name": "Aligned"
                },
                "properties": {
                    "platformUpdateDomainCount": 1,
                    "platformFaultDomainCount": 1
                }
            }
            if rppg:
                arm_avset["properties"]["proximityPlacementGroup"] = {
                    "id":
                    f"[resourceId('Microsoft.Compute/proximityPlacementGroups','{rppgname}')]"
                }
                arm_avset["dependsOn"] = [
                    f"Microsoft.Compute/proximityPlacementGroups/{rppgname}"
                ]
            self.resources.append(arm_avset)
            self.avsets.add(ravset)

        rorig = r
        for instance in range(1, rinstances + 1):
            if rinstances > 1:
                r = "{}{:04}".format(rorig, instance)

            nicdeps = []
            if vnet_in_deployment:
                nicdeps.append("Microsoft.Network/virtualNetworks/" + vnetname)

            if rpip:
                pipname = r + "_pip"
                if rdns:
                    dnsname = rdns
                else:
                    dnsname = azutil.get_dns_label(rrg, pipname, True)
                    if dnsname:
                        log.debug(f"dns name: {dnsname} (using existing one)")
                    else:
                        dnsname = r + str(uuid.uuid4())[:6]
                        log.debug(f"dns name: {dnsname}")
                nsgname = r + "_nsg"

                nicdeps.append("Microsoft.Network/publicIpAddresses/" +
                               pipname)
                nicdeps.append("Microsoft.Network/networkSecurityGroups/" +
                               nsgname)

                pipres = {
                    "type": "Microsoft.Network/publicIPAddresses",
                    "apiVersion": "2018-01-01",
                    "name": pipname,
                    "location": loc,
                    "dependsOn": [],
                    "tags": {},
                    "properties": {
                        "dnsSettings": {
                            "domainNameLabel": dnsname
                        }
                    }
                }
                self.__helper_arm_add_zones(pipres, raz)
                self.resources.append(pipres)

                nsg_security_rules = {
                    "rdp": {
                        "name": "default-allow-rdp",
                        "properties": {
                            "protocol": "Tcp",
                            "sourcePortRange": "*",
                            "destinationPortRange": "3389",
                            "sourceAddressPrefix": "*",
                            "destinationAddressPrefix": "*",
                            "access": "Allow",
                            "priority": 1000,
                            "direction": "Inbound"
                        }
                    },
                    "ssh": {
                        "name": "default-allow-ssh",
                        "properties": {
                            "protocol": "Tcp",
                            "sourcePortRange": "*",
                            "destinationPortRange": "22",
                            "sourceAddressPrefix": "*",
                            "destinationAddressPrefix": "*",
                            "access": "Allow",
                            "priority": 1010,
                            "direction": "Inbound"
                        }
                    },
                    "http": {
                        "name": "default-allow-http",
                        "properties": {
                            "protocol": "Tcp",
                            "sourcePortRange": "*",
                            "destinationPortRange": "80",
                            "sourceAddressPrefix": "*",
                            "destinationAddressPrefix": "*",
                            "access": "Allow",
                            "priority": 1020,
                            "direction": "Inbound"
                        }
                    },
                    "https": {
                        "name": "default-allow-https",
                        "properties": {
                            "protocol": "Tcp",
                            "sourcePortRange": "*",
                            "destinationPortRange": "443",
                            "sourceAddressPrefix": "*",
                            "destinationAddressPrefix": "*",
                            "access": "Allow",
                            "priority": 1030,
                            "direction": "Inbound"
                        }
                    }
                }

                if rnsgallow:
                    nsgrules = [
                        nsg_security_rules[service] for service in rnsgallow
                    ]
                else:
                    if ros[0] == "MicrosoftWindowsServer" or ros[
                            0] == "MicrosoftWindowsDesktop":
                        nsgrules = [nsg_security_rules["rdp"]]
                    else:
                        nsgrules = [nsg_security_rules["ssh"]]

                self.resources.append({
                    "type": "Microsoft.Network/networkSecurityGroups",
                    "apiVersion": "2015-06-15",
                    "name": nsgname,
                    "location": loc,
                    "dependsOn": [],
                    "tags": {},
                    "properties": {
                        "securityRules": nsgrules
                    }
                })

            nicname = r + "_nic"
            ipconfigname = r + "_ipconfig"
            nicprops = {
                "ipConfigurations": [{
                    "name": ipconfigname,
                    "properties": {
                        "privateIPAllocationMethod": "Dynamic",
                        "subnet": {
                            "id": rsubnetid
                        }
                    }
                }],
                "enableAcceleratedNetworking":
                ran
            }

            if rpip:
                nicprops["ipConfigurations"][0]["properties"][
                    "publicIPAddress"] = {
                        "id":
                        "[resourceId('Microsoft.Network/publicIPAddresses', '{}')]"
                        .format(pipname)
                    }
                nicprops["networkSecurityGroup"] = {
                    "id":
                    "[resourceId('Microsoft.Network/networkSecurityGroups', '{}')]"
                    .format(nsgname)
                }

            self.resources.append({
                "type": "Microsoft.Network/networkInterfaces",
                "apiVersion": "2016-09-01",
                "name": nicname,
                "location": loc,
                "dependsOn": nicdeps,
                "tags": {},
                "properties": nicprops
            })

            osprofile = self.__helper_arm_create_osprofile(
                r, rtype, adminuser, rpassword, sshkey, customdata)
            datadisks = self.__helper_arm_create_datadisks(
                rdatadisks, rstoragesku, rstoragecache)
            imageref = self.__helper_arm_create_image_reference(rimage)

            deps = [f"Microsoft.Network/networkInterfaces/{nicname}"]
            if rppg:
                deps.append(
                    f"Microsoft.Compute/proximityPlacementGroups/{rppgname}")
            if ravset:
                deps.append(f"Microsoft.Compute/availabilitySets/{ravset}")

            vmres = {
                "type": "Microsoft.Compute/virtualMachines",
                "apiVersion": "2019-07-01",
                "name": r,
                "location": loc,
                "dependsOn": deps,
                "tags": rtags,
                "properties": {
                    "hardwareProfile": {
                        "vmSize": rsize
                    },
                    "networkProfile": {
                        "networkInterfaces": [{
                            "id":
                            "[resourceId('Microsoft.Network/networkInterfaces', '{}')]"
                            .format(nicname)
                        }]
                    },
                    "storageProfile": {
                        "osDisk": {
                            "name": f"{r}_osdisk",
                            "createOption": "fromImage",
                            "caching": "ReadWrite",
                            "managedDisk": {
                                "storageAccountType": rosstoragesku
                            },
                        },
                        "imageReference": imageref,
                        "dataDisks": datadisks
                    },
                    "osProfile": osprofile
                }
            }

            if rlowpri:
                vmres["properties"]["priority"] = "Spot"
                vmres["properties"]["evictionPolicy"] = "Deallocate"

            if rppg:
                vmres["properties"]["proximityPlacementGroup"] = {
                    "id":
                    f"[resourceId('Microsoft.Compute/proximityPlacementGroups','{rppgname}')]"
                }

            if rstoragesku == "UltraSSD_LRS":
                vmres["properties"]["additionalCapabilities"] = {
                    "ultraSSDEnabled": True
                }

            if ravset:
                vmres["properties"]["availabilitySet"] = {
                    "id":
                    f"[resourceId('Microsoft.Compute/availabilitySets','{ravset}')]"
                }

            if rosdisksize:
                vmres["properties"]["storageProfile"]["osDisk"][
                    "diskSizeGb"] = rosdisksize

            if rmanagedidentity is not None:
                vmres["identity"] = {"type": "SystemAssigned"}

                role_lookup = {
                    "reader":
                    "[resourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]",
                    "contributor":
                    "[resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
                    "owner":
                    "[resourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]"
                }
                role = rmanagedidentity.get("role", "reader")
                if role not in role_lookup:
                    log.error(
                        f"{role} is an invalid role for a managed identity (options are: {', '.join(role_lookup.keys())})"
                    )
                    sys.exit(1)

                scope_lookup = {
                    "resource_group": "[resourceGroup().id]",
                    "subscription": "[subscription().subscriptionId]"
                }
                scope = rmanagedidentity.get("scope", "resource_group")
                if scope not in scope_lookup:
                    log.error(
                        f"{scope} is an invalid scope for a managed identity (options are: {', '.join(scope_lookup.keys())})"
                    )
                    sys.exit(1)

                self.resources.append({
                    "apiVersion":
                    "2017-09-01",
                    "type":
                    "Microsoft.Authorization/roleAssignments",
                    "name":
                    f"[guid(subscription().subscriptionId, resourceGroup().id, '{r}')]",
                    "properties": {
                        "roleDefinitionId": role_lookup[role],
                        "principalId":
                        f"[reference('{r}', '2017-12-01', 'Full').identity.principalId]",
                        "scope": scope_lookup[scope]
                    },
                    "dependsOn": [
                        f"[resourceId('Microsoft.Compute/virtualMachines/', '{r}')]"
                    ]
                })

            self.__helper_arm_add_zones(vmres, raz)
            self.resources.append(vmres)
Ejemplo n.º 2
0
    def _add_network(self, cfg):
        resource_group = cfg["resource_group"]
        vnet_resource_group = cfg["vnet"].get("resource_group", resource_group)
        if resource_group != vnet_resource_group:
            log.debug(f"using an existing vnet in {vnet_resource_group}")
            return

        location = cfg["location"]
        vnet_name = cfg["vnet"]["name"]
        address_prefix = cfg["vnet"]["address_prefix"]
        subnet_names = cfg["vnet"]["subnets"]
        subnets = []
        for subnet_name in subnet_names:
            subnet_address_prefix = cfg["vnet"]["subnets"][subnet_name]
            subnets.append({
                "name": subnet_name,
                "properties": {
                    "addressPrefix": subnet_address_prefix
                }
            })

        gtags = cfg.get("global_tags", {})

        res = {
            "apiVersion": "2018-10-01",
            "type": "Microsoft.Network/virtualNetworks",
            "name": vnet_name,
            "location": location,
            "tags": gtags,
            "properties": {
                "addressSpace": {
                    "addressPrefixes": [address_prefix]
                },
                "subnets": subnets
            }
        }
        self.resources.append(res)

        resource_group = cfg["resource_group"]
        for peer_name in cfg["vnet"].get("peer", {}).keys():
            peer_resource_group = cfg["vnet"]["peer"][peer_name][
                "resource_group"]
            peer_vnet_name = cfg["vnet"]["peer"][peer_name]["vnet_name"]

            self.resources.append({
                "type":
                "Microsoft.Network/virtualNetworks/virtualNetworkPeerings",
                "apiVersion":
                "2021-08-01",
                "name":
                f"{vnet_name}/{peer_name}-{peer_resource_group}",
                "properties": {
                    "remoteVirtualNetwork": {
                        "id":
                        f"[resourceId('{peer_resource_group}', 'Microsoft.Network/virtualNetworks', '{peer_vnet_name}')]"
                    },
                    "allowVirtualNetworkAccess": True,
                    "allowForwardedTraffic": True,
                    "allowGatewayTransit": False,
                    "useRemoteGateways": False,
                },
                "dependsOn":
                [f"Microsoft.Network/virtualNetworks/{vnet_name}"]
            })

            self.resources.append({
                "type":
                "Microsoft.Resources/deployments",
                "apiVersion":
                "2019-08-01",
                "name":
                f"{peer_resource_group}peer",
                "tags":
                gtags,
                "resourceGroup":
                peer_resource_group,
                "properties": {
                    "mode": "Incremental",
                    "template": {
                        "$schema":
                        "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                        "contentVersion":
                        "1.0.0.0",
                        "parameters": {},
                        "variables": {},
                        "resources": [{
                            "type":
                            "Microsoft.Network/virtualNetworks/virtualNetworkPeerings",
                            "apiVersion": "2021-08-01",
                            "name":
                            f"{peer_vnet_name}/{peer_name}-{resource_group}",
                            "properties": {
                                "remoteVirtualNetwork": {
                                    "id":
                                    f"[resourceId('{resource_group}', 'Microsoft.Network/virtualNetworks', '{vnet_name}')]"
                                },
                                "allowVirtualNetworkAccess": True,
                                "allowForwardedTraffic": True,
                                "allowGatewayTransit": False,
                                "useRemoteGateways": False
                            }
                        }],
                        "outputs": {}
                    },
                    "parameters": {}
                },
                "dependsOn":
                [f"Microsoft.Network/virtualNetworks/{vnet_name}"]
            })

        # private dns
        dns_domain = cfg["vnet"].get("dns_domain", None)
        if dns_domain:
            log.info(f"add private dns ({dns_domain})")
            self.resources.append({
                "type":
                "Microsoft.Network/privateDnsZones",
                "apiVersion":
                "2018-09-01",
                "name":
                dns_domain,
                "tags":
                gtags,
                "location":
                "global",
                "properties": {},
                "resources": [{
                    "type":
                    "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
                    "apiVersion":
                    "2018-09-01",
                    "name":
                    f"[concat('{dns_domain}', '/{vnet_name}')]",
                    "location":
                    "global",
                    "dependsOn": [
                        f"[resourceId('Microsoft.Network/privateDnsZones', '{dns_domain}')]"
                    ],
                    "properties": {
                        "registrationEnabled": True,
                        "virtualNetwork": {
                            "id":
                            f"[resourceId('Microsoft.Network/virtualNetworks', '{vnet_name}')]"
                        }
                    }
                }]
            })

        # add route tables first (and keep track of mapping to subnet)
        route_table_map = {}
        for route_name in cfg["vnet"].get("routes", {}).keys():
            route_address_prefix = cfg["vnet"]["routes"][route_name][
                "address_prefix"]
            route_next_hop = cfg["vnet"]["routes"][route_name]["next_hop"]
            route_subnet = cfg["vnet"]["routes"][route_name]["subnet"]

            route_table_map[route_subnet] = route_name

            self.resources.append({
                "type":
                "Microsoft.Network/routeTables",
                "apiVersion":
                "2019-11-01",
                "name":
                route_name,
                "tags":
                gtags,
                "location":
                location,
                "properties": {
                    "disableBgpRoutePropagation":
                    False,
                    "routes": [{
                        "name": route_name,
                        "properties": {
                            "addressPrefix":
                            route_address_prefix,
                            "nextHopType":
                            "VirtualAppliance",
                            "nextHopIpAddress":
                            f"[reference('{route_next_hop}_nic').ipConfigurations[0].properties.privateIPAddress]"
                        }
                    }]
                },
                "dependsOn":
                [f"Microsoft.Network/networkInterfaces/{route_next_hop}_nic"]
            })
            self.resources.append({
                "type":
                "Microsoft.Network/routeTables/routes",
                "apiVersion":
                "2019-11-01",
                "name":
                f"{route_name}/{route_name}",
                "dependsOn": [
                    f"[resourceId('Microsoft.Network/routeTables', '{route_name}')]"
                ],
                "properties": {
                    "addressPrefix":
                    route_address_prefix,
                    "nextHopType":
                    "VirtualAppliance",
                    "nextHopIpAddress":
                    f"[reference('{route_next_hop}_nic').ipConfigurations[0].properties.privateIPAddress]"
                }
            })
            subnet_address_prefix = cfg["vnet"]["subnets"][route_subnet]
            self.resources.append({
                "type":
                "Microsoft.Network/virtualNetworks/subnets",
                "apiVersion":
                "2019-11-01",
                "name":
                f"{vnet_name}/{route_subnet}",
                "dependsOn": [
                    f"[resourceId('Microsoft.Network/routeTables', '{route_name}')]"
                ],
                "properties": {
                    "addressPrefix": subnet_address_prefix,
                    "routeTable": {
                        "id":
                        f"[resourceId('Microsoft.Network/routeTables', '{route_name}')]"
                    }
                }
            })

        # vpn gateway
        vpn_gateway_name = cfg["vnet"].get("gateway", {}).get("name", None)
        if vpn_gateway_name:
            log.info(f"add vpn gateway ({vpn_gateway_name})")
            rrg = cfg["resource_group"]
            vnetname = cfg["vnet"]["name"]
            subnet = cfg["vnet"]["gateway"].get("subnet")
            aad_tenant = cfg["vnet"]["gateway"].get("aad_tenant")
            aad_audience = cfg["vnet"]["gateway"].get("aad_audience")
            aad_issuer = cfg["vnet"]["gateway"].get("aad_issuer")
            nicdeps = []
            pipname = vpn_gateway_name + "_pip"
            dnsname = azutil.get_dns_label(rrg, pipname, True)
            if dnsname:
                log.debug(f"dns name: {dnsname} (using existing one)")
            else:
                dnsname = vpn_gateway_name + str(uuid.uuid4())[:6]
                log.debug(f"dns name: {dnsname}")

            nicdeps.append("Microsoft.Network/publicIpAddresses/" + pipname)

            pipres = {
                "type": "Microsoft.Network/publicIPAddresses",
                "apiVersion": "2018-01-01",
                "name": pipname,
                "location": location,
                "dependsOn": [],
                "tags": gtags,
                "properties": {
                    "dnsSettings": {
                        "domainNameLabel": dnsname
                    }
                }
            }
            self.resources.append(pipres)

            self.resources.append({
                "type":
                "Microsoft.Network/virtualNetworkGateways",
                "apiVersion":
                "2020-11-01",
                "name":
                vpn_gateway_name,
                "tags":
                gtags,
                "location":
                location,
                "properties": {
                    "enablePrivateIpAddress":
                    False,
                    "ipConfigurations": [{
                        "name": "default",
                        "properties": {
                            "privateIPAllocationMethod": "Dynamic",
                            "publicIPAddress": {
                                "id":
                                "[resourceId('Microsoft.Network/publicIPAddresses', '{}')]"
                                .format(pipname)
                            },
                            "subnet": {
                                "id":
                                "[resourceId('Microsoft.Network/virtualNetworks/subnets', '{}', '{}')]"
                                .format(vnetname, subnet)
                            }
                        }
                    }],
                    "sku": {
                        "name": "VpnGw2",
                        "tier": "VpnGw2"
                    },
                    "gatewayType":
                    "Vpn",
                    "vpnType":
                    "RouteBased",
                    "enableBgp":
                    False,
                    "activeActive":
                    False,
                    "vpnClientConfiguration": {
                        "vpnClientAddressPool": {
                            "addressPrefixes": ["172.0.0.0/24"]
                        },
                        "vpnClientProtocols": ["OpenVPN"],
                        "vpnAuthenticationTypes": ["AAD"],
                        "vpnClientRootCertificates": [],
                        "vpnClientRevokedCertificates": [],
                        "radiusServers": [],
                        "vpnClientIpsecPolicies": [],
                        "aadTenant": aad_tenant,
                        "aadAudience": aad_audience,
                        "aadIssuer": aad_issuer
                    },
                    "bgpSettings": {
                        "asn":
                        65515,
                        "bgpPeeringAddress":
                        "10.0.4.254",
                        "peerWeight":
                        0,
                        "bgpPeeringAddresses": [{
                            "ipconfigurationId":
                            "[concat(resourceId('Microsoft.Network/virtualNetworkGateways', '{}'), '/ipConfigurations/default')]"
                            .format(vpn_gateway_name),
                            "customBgpIpAddresses": []
                        }]
                    },
                    "vpnGatewayGeneration":
                    "Generation2"
                },
                "dependsOn": [
                    f"[resourceId('Microsoft.Network/publicIPAddresses', '{pipname}' )]",
                    f"Microsoft.Network/virtualNetworks/{vnetname}"
                ]
            })