├── Azure_DMZ_To_Onprem ├── README.md ├── as3.json ├── cluster.json ├── dmz-private.png ├── main.tf ├── onboard.tpl ├── provider.tf └── variables.tf ├── Azure_Secure_Enclave_Public_DMZ ├── README.md ├── Secure_Enclave_public_dmz.png ├── as3.json ├── cluster.json ├── link_LAW_to_Sentinel.png ├── main.tf ├── onboard.tpl ├── open_workbook_template.png ├── provider.tf ├── ts.json └── variables.tf ├── HA_via_api ├── AzureFailoverExtensionHighLevel1.gif ├── README.md ├── as3.json ├── cluster.json ├── failover.json ├── main.tf ├── onboard.tpl ├── provider.tf └── variables.tf ├── HA_via_lb_DO_AS3 ├── .terraform │ └── plugins │ │ └── linux_386 │ │ ├── lock.json │ │ ├── terraform-provider-azurerm_v1.21.0_x4 │ │ └── terraform-provider-template_v2.0.0_x4 ├── HA_via_lb_2nics.png ├── README.md ├── as3.json ├── cluster.json ├── main.tf ├── onboard.tpl ├── provider.tf └── variables.tf └── README.md /Azure_DMZ_To_Onprem/README.md: -------------------------------------------------------------------------------- 1 | # Deploying a Azure Private DMZ zone with a pair of Active/Standby BIG-IP VEs 2 | 3 | ## Contents 4 | 5 | - [Introduction](#introduction) 6 | - [Prerequisites](#prerequisites) 7 | - [Important Configuration Notes](#important-configuration-notes) 8 | - [Security](#security) 9 | - [Configuration Example](#configuration-example) 10 | 11 | ## Introduction 12 | This reference architecture shows a secure hybrid network that extends an on-premises network to Azure. The architecture implements a DMZ, also called a perimeter network, between the on-premises network and an Azure virtual network (VNet). The DMZ includes network virtual appliances (NVAs) that implement security functionality such as firewalls and packet inspection. 13 | 14 | This solution uses an Terraform template to launch a two NIC deployment of a cloud-focused BIG-IP VE cluster (Active/Standby) in Microsoft Azure. Traffic flows from an ALB to the BIG-IP VE which then processes the traffic to application servers. This is the standard cloud design where the BIG-IP VE instance is running with a dual interface, where both management and data plane traffic is processed on each one. 15 | 16 | The BIG-IP VEs have the [Local Traffic Manager (LTM)](https://f5.com/products/big-ip/local-traffic-manager-ltm) module enabled to provide advanced traffic management functionality. This means you can also configure the BIG-IP VE to enable F5's L4/L7 security features, access control, and intelligent traffic management. 17 | 18 | **Networking Stack Type:** This solution deploys into a new networking stack, which is created along with the solution. 19 | 20 | ## Prerequisites 21 | - On-premises network. A private local-area network implemented in an organization. 22 | - Gateway. The gateway provides connectivity between the routers in the on-premises network and the VNet. 23 | - User defined routes (UDR). User defined routes define the flow of IP traffic within Azure VNets 24 | - **Important**: When you configure the admin password for the BIG-IP VE in the template, you cannot use the character **#**. Additionally, there are a number of other special characters that you should avoid using for F5 product user accounts. See [K2873](https://support.f5.com/csp/article/K2873) for details. 25 | - This template requires a service principal. See the [Service Principal Setup section](#service-principal-authentication) for details, including required permissions. 26 | - This deployment will be using the Terraform Azurerm provider to build out all the neccessary Azure objects. Therefore, Azure CLI is required. for installation, please follow this [Microsoft link](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-apt?view=azure-cli-latest) 27 | - If this is the first time to deploy the F5 image, the subscription used in this deployment needs to be enabled to programatically deploy. For more information, please refer to [Configure Programatic Deployment](https://azure.microsoft.com/en-us/blog/working-with-marketplace-images-on-azure-resource-manager/) 28 | 29 | ## Important configuration notes 30 | 31 | - All variables are configured in variables.tf 32 | - Azure Subscription and Service Principal are configured in provider.tf 33 | - This template would require Declarative Onboarding and AS3 packages for the initial configuration. As part of the onboarding script, it will download the RPMs respectively. So please see the [AS3 documentation](https://clouddocs.f5.com/products/extensions/f5-appsvcs-extension/3.5.1/) and [DO documentation](https://clouddocs.f5.com/products/extensions/f5-declarative-onboarding/latest/prereqs.html) for details on how to use AS3 and Declarative Onboarding on your BIG-IP VE(s). 34 | - onboard.tpl is the onboarding script, which is run by commandToExecute, and it will be copy to /var/lib/waagent/CustomData upon bootup. This script is basically responsible for downloading the neccessary DO and AS3 RPM files, installing them, and then executing the onboarding REST calls. 35 | - This template uses PayGo BIGIP image for the deployment (as default). If you would like to use BYOL, then these following steps are needed: 36 | 1. In the "variable.tf", specify the BYOL image and licenses regkeys. 37 | 2. In the "main.tf", uncomment the "local_sku" lines. 38 | 3. Add the following lines to the "cluster.json" file just under the "Common" declaration: 39 | ``` 40 | "myLicense": { 41 | "class": "License", 42 | "licenseType": "regKey", 43 | "regKey": "${local_sku}" 44 | }, 45 | ``` 46 | - In order to pass traffic from your clients to the servers, after launching the template, you must create virtual server(s) on the BIG-IP VE. See [Creating a virtual server](#creating-virtual-servers-on-the-big-ip-ve). 47 | - See the **[Configuration Example](#configuration-example)** section for a configuration diagram and description for this solution. 48 | 49 | ### Template parameters 50 | 51 | | Parameter | Required | Description | 52 | | --- | --- | --- | 53 | | prefix | Yes | This value is insert in the beginning of each Azure object, try keeps it alpha-numeric without any special character | 54 | | onpremsite1 | Yes | On-prem VPN endpoint public IP, address spaces, and sharekey. | 55 | | lb_ip | Yes | Private IP address to allocate for the Azure Load Balancer | 56 | | uname | Yes | User name for the Virtual Machine. | 57 | | upassword | Yes | Password for the Virtual Machine. | 58 | | location | Yes | Location of the deployment. | 59 | | region | Yes | Region of the deployment. | 60 | | cidr | Yes | IP Address range of the Virtual Network. | 61 | | subnet1 | Yes | Subnet IP range of the management network. | 62 | | subnet2 | Yes | Subnet IP range of the external network. | 63 | | subnet3 | No | Subnet IP range of the internal network. | 64 | | gwsubnet | Yes | Subnet IP range of the Transit Gateway. | 65 | | f5vm01mgmt | Yes | IP address for 1st BIG-IP's management interface. | 66 | | f5vm02mgmt | Yes | IP address for 2nd BIG-IP's management interface. | 67 | | f5vm01ext | Yes | IP address for 1st BIG-IP's external interface. | 68 | | f5vm01ext_sec | Yes | Secondary IP address for 1st BIG-IP's external interface. | 69 | | f5vm02ext | Yes | IP address for 2nd BIG-IP's external interface. | 70 | | f5vm02ext_sec | Yes | Secondary IP address for 2nd BIG-IP's external interface. | 71 | | instance_type | Yes | Azure instance to be used for the BIG-IP VE. | 72 | | product | Yes | Azure BIG-IP VE Offer. | 73 | | bigip_version | Yes | It is set to default to use the latest software. | 74 | | image_name | Yes | F5 SKU (image) to you want to deploy. Note: The disk size of the VM will be determined based on the option you select. **Important**: If intending to provision multiple modules, ensure the appropriate value is selected, such as ****AllTwoBootLocations or AllOneBootLocation****. | 75 | | license1 | No | The license token for the F5 BIG-IP VE (BYOL). | 76 | | license2 | No | The license token for the F5 BIG-IP VE (BYOL). | 77 | | host1_name | Yes | Hostname for the 1st BIG-IP. | 78 | | host2_name | Yes | Hostname for the 2nd BIG-IP. | 79 | | ntp_server | Yes | Leave the default NTP server the BIG-IP uses, or replace the default NTP server with the one you want to use. | 80 | | timezone | Yes | If you would like to change the time zone the BIG-IP uses, enter the time zone you want to use. This is based on the tz database found in /usr/share/zoneinfo (see the full list [here](https://github.com/F5Networks/f5-azure-arm-templates/blob/master/azure-timezone-list.md)). Example values: UTC, US/Pacific, US/Eastern, Europe/London or Asia/Singapore. | 81 | | dns_server | Yes | Least the default DNS server the BIG-IP uses, or replace the default DNS server with the one you want to use. | 82 | | DO_onboard_URL | Yes | This is the raw github URL for downloading the Declarative Onboarding RPM | 83 | | AS3_URL | Yes | This is the raw github URL for downloading the AS3 RPM. | 84 | | libs_dir | Yes | This is where all the temporary libs and RPM will be store in BIG-IP. | 85 | | onboard_log | Yes | This is where the onboarding script logs all the events. | 86 | 87 | ======= 88 | 89 | #### Azure CLI (1.0) Script Example 90 | 91 | ```bash 92 | ## Example Command: ./deploy_via_bash.sh --numberOfInstances 2 --adminUsername azureuser --authenticationType password --adminPasswordOrKey --dnsLabel --instanceType Standard_DS2_v2 --imageName AllTwoBootLocations --bigIpVersion 13.1.100000 --licenseKey1 --licenseKey2 --vnetAddressPrefix 10.0 --ntpServer 0.pool.ntp.org --timeZone UTC --customImage OPTIONAL --allowUsageAnalytics Yes --resourceGroupName --azureLoginUser --azureLoginPassword 93 | ``` 94 | 95 | ## Configuration Example 96 | 97 | The following is an example configuration diagram for this solution deployment. In this scenario, all access to the BIG-IP VE cluster (Active/Standby) is through an ALB. The IP addresses in this example may be different in your implementation. Please check the [Reference Architecture](https://docs.microsoft.com/en-us/azure/architecture/reference-architectures/dmz/secure-vnet-hybrid) for detail 98 | 99 | ![Configuration Example](./dmz-private.png) 100 | 101 | 102 | ## Documentation 103 | 104 | For more information on F5 solutions for Azure, including manual configuration procedures for some deployment scenarios, see the Azure section of [Public Cloud Docs](http://clouddocs.f5.com/cloud/public/v1/). 105 | 106 | ## Creating virtual servers on the BIG-IP VE 107 | 108 | In order to pass traffic from your clients to the servers through the BIG-IP system, you must create a virtual server on the BIG-IP VE. 109 | 110 | In this template, the Azure public IP address is associated with an Azure Load Balancer that forwards traffic to a backend pool that includes the primary (self) IP configurations for *each* BIG-IP network interface. Because traffic is destined for the self IP addresses of the BIG-IP VEs, you must create a single virtual server with a wildcard destination in Traffic Group **None**. 111 | 112 | 1. Once your BIG-IP VE has launched, open the BIG-IP VE Configuration utility. 113 | 2. On the Main tab, click **Local Traffic > Virtual Servers** and then click the **Create** button. 114 | 3. In the **Name** field, give the Virtual Server a unique name. 115 | 4. In the **Destination/Mask** field, type the destination address ( for example: 0.0.0.0/0). 116 | 5. In the **Service Port** field, type the appropriate port. 117 | 6. Configure the rest of the virtual server as appropriate. 118 | 7. If you used the Service Discovery iApp template: In the Resources section, from the **Default Pool** list, select the name of the pool created by the iApp. 119 | 8. Click the **Finished** button. 120 | 9. Repeat as necessary. 121 | 122 | When you have completed the virtual server configuration, you must modify the virtual addresses to use Traffic Group None using the following guidance. 123 | 124 | 1. On the Main tab, click **Local Traffic > Virtual Servers**. 125 | 2. On the Menu bar, click the **Virtual Address List** tab. 126 | 3. Click the address of one of the virtual servers you just created. 127 | 4. From the **Traffic Group** list, select **None**. 128 | 5. Click **Update**. 129 | 6. Repeat for each virtual server. 130 | 131 | -------------------------------------------------------------------------------- /Azure_DMZ_To_Onprem/as3.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "AS3", 3 | "action": "deploy", 4 | "persist": true, 5 | "declaration": { 6 | "class": "ADC", 7 | "schemaVersion": "3.0.0", 8 | "id": "123abc", 9 | "label": "Sample 1", 10 | "remark": "HTTPS with predictive-node pool", 11 | "Sample_01": { 12 | "class": "Tenant", 13 | "Shared": { 14 | "class":"Application", 15 | "template":"shared", 16 | "serviceAddress": { 17 | "class":"Service_Address", 18 | "virtualAddress":"0.0.0.0"} 19 | }, 20 | "A1": { 21 | "class": "Application", 22 | "template": "https", 23 | "serviceMain": { 24 | "class": "Service_HTTPS", 25 | "virtualPort": 8443, 26 | "virtualAddresses": [{ 27 | "use":"/Sample_01/Shared/serviceAddress" 28 | }], 29 | "pool": "web_pool", 30 | "serverTLS": "webtls" 31 | }, 32 | "web_pool": { 33 | "class": "Pool", 34 | "loadBalancingMode": "predictive-node", 35 | "members": [{ 36 | "servicePort": 80, 37 | "serverAddresses": [ 38 | "192.0.2.12", 39 | "192.0.2.13" 40 | ] 41 | }] 42 | }, 43 | "webtls": { 44 | "class": "TLS_Server", 45 | "certificates": [{ 46 | "certificate": "webcert" 47 | }] 48 | }, 49 | "webcert": { 50 | "class": "Certificate", 51 | "remark": "in practice we recommend using a passphrase", 52 | "certificate": "-----BEGIN CERTIFICATE-----\nMIICnDCCAgWgAwIBAgIJAJ5n2b0OCEjwMA0GCSqGSIb3DQEBCwUAMGcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMRQwEgYDVQQKDAtmNV9OZXR3b3JrczEbMBkGA1UEAwwSc2FtcGxlLmV4YW1wbGUubmV0MB4XDTE3MTEyNjE5NTAyNFoXDTE4MDIyNTE5NTAyNFowZzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxFDASBgNVBAoMC2Y1X05ldHdvcmtzMRswGQYDVQQDDBJzYW1wbGUuZXhhbXBsZS5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALEsuXmSXVQpYjrZPW+WiTBjn491mwZYT7Q92V1HlSBtM6WdWlK1aZN5sovfKtOX7Yrm8xa+e4o/zJ2QYLyyv5O+t2EGN/4qUEjEAPY9mwJdfzRQy6Hyzm84J0QkTuUJ/EjNuPji3D0QJRALUTzu1UqqDCEtiN9OGyXEkh7uvb7BAgMBAAGjUDBOMB0GA1UdDgQWBBSVHPNrGWrjWyZvckQxFYWO59FRFjAfBgNVHSMEGDAWgBSVHPNrGWrjWyZvckQxFYWO59FRFjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBAJeJ9SEckEwPhkXOm+IuqfbUS/RcziifBCTmVyE+Fa/j9pKSYTgiEBNdbJeBEa+gPMlQtbV7Y2dy8TKx/8axVBHiXC5geDML7caxOrAyHYBpnx690xJTh5OIORBBM/a/NvaR+P3CoVebr/NPRh9oRNxnntnqvqD7SW0U3ZPe3tJc\n-----END CERTIFICATE-----", 53 | "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-256-CBC,D8FFCE6B255601587CB54EC29B737D31\n\nkv4Fc3Jn0Ujkj0yRjt+gQQfBLSNF2aRLUENXnlr7Xpzqu0Ahr3jS1bAAnd8IWnsR\nyILqVmKsYF2DoHh0tWiEAQ7/y/fe5DTFhK7N4Wml6kp2yVMkP6KC4ssyYPw27kjK\nDBwBZ5O8Ioej08A5sgsLCmglbmtSPHJUn14pQnMTmLOpEtOsu6S+2ibPgSNpdg0b\nCAJNG/KHe+Vkx59qNDyDeKb7FZOlsX30+y67zUq9GQqJEDuysPJ2BUNP0IJXAjst\nFIt1qNoZew+5KDYs7u/lPxcMGTirUhgI84Jy4WcDvSOsP/tKlxj04TbIE3epmSKy\n+TihHkwY7ngIGtcm3Sfqk5jz2RXoj1/Ac3SW8kVTYaOUogBhn7zAq4Wju6Et4hQG\nRGapsJp1aCeZ/a4RCDTxspcKoMaRa97/URQb0hBRGx3DGUhzpmX9zl7JI2Xa5D3R\nmdBXtjLKYJTdIMdd27prBEKhMUpae2rz5Mw4J907wZeBq/wu+zp8LAnecfTe2nGY\nE32x1U7gSEdYOGqnwxsOexb1jKgCa67Nw9TmcMPV8zmH7R9qdvgxAbAtwBl1F9OS\nfcGaC7epf1AjJLtaX7krWmzgASHl28Ynh9lmGMdv+5QYMZvKG0LOg/n3m8uJ6sKy\nIzzvaJswwn0j5P5+czyoV5CvvdCfKnNb+3jUEN8I0PPwjBGKr4B1ojwhogTM248V\nHR69D6TxFVMfGpyJhCPkbGEGbpEpcffpgKuC/mEtMqyDQXJNaV5HO6HgAJ9F1P6v\n5ehHHTMRvzCCFiwndHdlMXUjqSNjww6me6dr6LiAPbejdzhL2vWx1YqebOcwQx3G\n-----END RSA PRIVATE KEY-----", 54 | "passphrase": { 55 | "ciphertext": "ZjVmNQ==", 56 | "protected": "eyJhbGciOiJkaXIiLCJlbmMiOiJub25lIn0" 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /Azure_DMZ_To_Onprem/cluster.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0.0", 3 | "class": "Device", 4 | "label": "Basic onboarding", 5 | "Common": { 6 | "class": "Tenant", 7 | "hostname": "${local_host}.example.com", 8 | "dbvars": { 9 | "class": "DbVariables", 10 | "ui.advisory.enabled": true, 11 | "ui.advisory.color": "green", 12 | "ui.advisory.text": "/Common/hostname" 13 | }, 14 | "myDns": { 15 | "class": "DNS", 16 | "nameServers": [ 17 | "${dns_server}", 18 | "2001:4860:4860::8844" 19 | ], 20 | "search": [ 21 | "f5.com" 22 | ] 23 | }, 24 | "myNtp": { 25 | "class": "NTP", 26 | "servers": [ 27 | "${ntp_server}", 28 | "0.pool.ntp.org", 29 | "1.pool.ntp.org" 30 | ], 31 | "timezone": "${timezone}" 32 | }, 33 | "myProvisioning": { 34 | "class": "Provision", 35 | "ltm": "nominal" 36 | }, 37 | "external": { 38 | "class": "VLAN", 39 | "tag": 4094, 40 | "mtu": 1500, 41 | "interfaces": [ 42 | { 43 | "name": "1.1", 44 | "tagged": false 45 | } 46 | ] 47 | }, 48 | "external-self": { 49 | "class": "SelfIp", 50 | "address": "${local_selfip}/24", 51 | "vlan": "external", 52 | "allowService": "default", 53 | "trafficGroup": "traffic-group-local-only" 54 | }, 55 | "default": { 56 | "class": "Route", 57 | "gw": "${gateway}", 58 | "network": "default", 59 | "mtu": 1500 60 | }, 61 | "configsync": { 62 | "class": "ConfigSync", 63 | "configsyncIp": "/Common/external-self/address" 64 | }, 65 | "failoverAddress": { 66 | "class": "FailoverUnicast", 67 | "address": "/Common/external-self/address" 68 | }, 69 | "failoverGroup": { 70 | "class": "DeviceGroup", 71 | "type": "sync-failover", 72 | "members": ["${host1}.example.com", "${host2}.example.com"], 73 | "owner": "/Common/failoverGroup/members/0", 74 | "autoSync": true, 75 | "saveOnAutoSync": false, 76 | "networkFailover": true, 77 | "fullLoadOnSync": false, 78 | "asmSync": false 79 | }, 80 | "trust": { 81 | "class": "DeviceTrust", 82 | "localUsername": "${admin_user}", 83 | "localPassword": "${admin_password}", 84 | "remoteHost": "${remote_selfip}", 85 | "remoteUsername": "${admin_user}", 86 | "remotePassword": "${admin_password}" 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Azure_DMZ_To_Onprem/dmz-private.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garyluf5/f5_terraform/ab4ceb4c754d507d4db96b30cbb75ac53e30d61f/Azure_DMZ_To_Onprem/dmz-private.png -------------------------------------------------------------------------------- /Azure_DMZ_To_Onprem/main.tf: -------------------------------------------------------------------------------- 1 | # Create a Resource Group for the new Virtual Machine 2 | resource "azurerm_resource_group" "main" { 3 | name = "${var.prefix}_rg" 4 | location = "${var.location}" 5 | } 6 | 7 | # Create a Virtual Network for Private DMZ 8 | resource "azurerm_virtual_network" "main" { 9 | name = "${var.prefix}-network" 10 | address_space = ["${var.cidr}"] 11 | resource_group_name = "${azurerm_resource_group.main.name}" 12 | location = "${azurerm_resource_group.main.location}" 13 | } 14 | 15 | # Create a gwsubnet subnet for Transit Gateway 16 | resource "azurerm_subnet" "GatewaySubnet" { 17 | name = "GatewaySubnet" 18 | virtual_network_name = "${azurerm_virtual_network.main.name}" 19 | resource_group_name = "${azurerm_resource_group.main.name}" 20 | address_prefix = "${var.subnets["gwsubnet"]}" 21 | } 22 | 23 | # Create the first Subnet within the Private DMZ Virtual Network 24 | resource "azurerm_subnet" "Mgmt" { 25 | name = "Mgmt" 26 | virtual_network_name = "${azurerm_virtual_network.main.name}" 27 | resource_group_name = "${azurerm_resource_group.main.name}" 28 | address_prefix = "${var.subnets["subnet1"]}" 29 | } 30 | 31 | # Create the second Subnet within the Private DMZ Virtual Network 32 | resource "azurerm_subnet" "External" { 33 | name = "External" 34 | virtual_network_name = "${azurerm_virtual_network.main.name}" 35 | resource_group_name = "${azurerm_resource_group.main.name}" 36 | address_prefix = "${var.subnets["subnet2"]}" 37 | } 38 | 39 | # Create a Public IP for the Virtual Machines 40 | resource "azurerm_public_ip" "vm01mgmtpip" { 41 | name = "${var.prefix}-vm01-mgmt-pip" 42 | location = "${azurerm_resource_group.main.location}" 43 | resource_group_name = "${azurerm_resource_group.main.name}" 44 | allocation_method = "Dynamic" 45 | 46 | tags { 47 | Name = "${var.environment}-vm01-mgmt-public-ip" 48 | environment = "${var.environment}" 49 | owner = "${var.owner}" 50 | group = "${var.group}" 51 | costcenter = "${var.costcenter}" 52 | application = "${var.application}" 53 | } 54 | } 55 | 56 | resource "azurerm_public_ip" "vm02mgmtpip" { 57 | name = "${var.prefix}-vm02-mgmt-pip" 58 | location = "${azurerm_resource_group.main.location}" 59 | resource_group_name = "${azurerm_resource_group.main.name}" 60 | allocation_method = "Dynamic" 61 | 62 | tags { 63 | Name = "${var.environment}-vm02-mgmt-public-ip" 64 | environment = "${var.environment}" 65 | owner = "${var.owner}" 66 | group = "${var.group}" 67 | costcenter = "${var.costcenter}" 68 | application = "${var.application}" 69 | } 70 | } 71 | 72 | resource "azurerm_public_ip" "tgwpip" { 73 | name = "${var.prefix}-tgw-pip" 74 | location = "${azurerm_resource_group.main.location}" 75 | resource_group_name = "${azurerm_resource_group.main.name}" 76 | allocation_method = "Dynamic" 77 | 78 | tags { 79 | Name = "${var.environment}-tgw-public-ip" 80 | environment = "${var.environment}" 81 | owner = "${var.owner}" 82 | group = "${var.group}" 83 | costcenter = "${var.costcenter}" 84 | application = "${var.application}" 85 | } 86 | } 87 | 88 | # Create Local Network Gateway 89 | resource "azurerm_local_network_gateway" "onpremise1" { 90 | name = "onpremise1" 91 | location = "${azurerm_resource_group.main.location}" 92 | resource_group_name = "${azurerm_resource_group.main.name}" 93 | gateway_address = "${var.onpremsite1["publicip"]}" 94 | address_space = ["${var.onpremsite1["addrspace1"]}", "${var.onpremsite1["addrspace2"]}"] 95 | } 96 | 97 | # Create Azure VPN Gateway 98 | resource "azurerm_virtual_network_gateway" "site1" { 99 | name = "site1" 100 | location = "${azurerm_resource_group.main.location}" 101 | resource_group_name = "${azurerm_resource_group.main.name}" 102 | depends_on = ["azurerm_public_ip.tgwpip"] 103 | 104 | type = "Vpn" 105 | vpn_type = "RouteBased" 106 | 107 | active_active = false 108 | enable_bgp = false 109 | sku = "VpnGw1" 110 | 111 | ip_configuration { 112 | public_ip_address_id = "${azurerm_public_ip.tgwpip.id}" 113 | private_ip_address_allocation = "Dynamic" 114 | subnet_id = "${azurerm_subnet.GatewaySubnet.id}" 115 | } 116 | } 117 | 118 | # Connect to On-prem Site1 119 | resource "azurerm_virtual_network_gateway_connection" "onpremise1" { 120 | name = "onpremise1" 121 | location = "${azurerm_resource_group.main.location}" 122 | resource_group_name = "${azurerm_resource_group.main.name}" 123 | 124 | type = "IPsec" 125 | virtual_network_gateway_id = "${azurerm_virtual_network_gateway.site1.id}" 126 | local_network_gateway_id = "${azurerm_local_network_gateway.onpremise1.id}" 127 | 128 | shared_key = "${var.onpremsite1["sharekey"]}" 129 | 130 | } 131 | 132 | # Create a custom Route Table for Gateway Subnet 133 | resource "azurerm_route_table" "gwrt" { 134 | name = "gwrt" 135 | location = "${azurerm_resource_group.main.location}" 136 | resource_group_name = "${azurerm_resource_group.main.name}" 137 | disable_bgp_route_propagation = false 138 | 139 | # This route is using Azure LB IP address as the next hop 140 | route { 141 | name = "route1" 142 | # This route is configured depending on the specific usecase 143 | address_prefix = "20.90.0.0/16" 144 | next_hop_type = "VirtualAppliance" 145 | next_hop_in_ip_address = "${var.lb_ip}" 146 | } 147 | 148 | tags { 149 | environment = "Production" 150 | } 151 | } 152 | 153 | resource "azurerm_subnet_route_table_association" "gwrt-GWS" { 154 | subnet_id = "${azurerm_subnet.GatewaySubnet.id}" 155 | route_table_id = "${azurerm_route_table.gwrt.id}" 156 | } 157 | 158 | # Obtain Gateway IP for each Private DMZ Subnet 159 | locals { 160 | depends_on = ["azurerm_subnet.Mgmt", "azurerm_subnet.External"] 161 | mgmt_gw = "${cidrhost(azurerm_subnet.Mgmt.address_prefix, 1)}" 162 | ext_gw = "${cidrhost(azurerm_subnet.External.address_prefix, 1)}" 163 | } 164 | 165 | # Create Availability Set 166 | resource "azurerm_availability_set" "avset" { 167 | name = "${var.prefix}avset" 168 | location = "${azurerm_resource_group.main.location}" 169 | resource_group_name = "${azurerm_resource_group.main.name}" 170 | platform_fault_domain_count = 2 171 | platform_update_domain_count = 2 172 | managed = true 173 | } 174 | 175 | # Create Azure LB 176 | resource "azurerm_lb" "lb" { 177 | name = "${var.prefix}lb" 178 | location = "${azurerm_resource_group.main.location}" 179 | resource_group_name = "${azurerm_resource_group.main.name}" 180 | 181 | frontend_ip_configuration { 182 | name = "LoadBalancerFrontEnd" 183 | subnet_id = "${azurerm_subnet.External.id}" 184 | private_ip_address_allocation = "Static" 185 | private_ip_address = "${var.lb_ip}" 186 | } 187 | } 188 | 189 | resource "azurerm_lb_backend_address_pool" "backend_pool" { 190 | name = "BackendPool1" 191 | resource_group_name = "${azurerm_resource_group.main.name}" 192 | loadbalancer_id = "${azurerm_lb.lb.id}" 193 | } 194 | 195 | resource "azurerm_lb_probe" "lb_probe" { 196 | resource_group_name = "${azurerm_resource_group.main.name}" 197 | loadbalancer_id = "${azurerm_lb.lb.id}" 198 | name = "tcpProbe" 199 | protocol = "tcp" 200 | port = 8443 201 | interval_in_seconds = 5 202 | number_of_probes = 2 203 | } 204 | 205 | resource "azurerm_lb_rule" "lb_rule" { 206 | name = "LBRule" 207 | resource_group_name = "${azurerm_resource_group.main.name}" 208 | loadbalancer_id = "${azurerm_lb.lb.id}" 209 | protocol = "tcp" 210 | frontend_port = 443 211 | backend_port = 8443 212 | frontend_ip_configuration_name = "LoadBalancerFrontEnd" 213 | enable_floating_ip = false 214 | backend_address_pool_id = "${azurerm_lb_backend_address_pool.backend_pool.id}" 215 | idle_timeout_in_minutes = 5 216 | probe_id = "${azurerm_lb_probe.lb_probe.id}" 217 | depends_on = ["azurerm_lb_probe.lb_probe"] 218 | } 219 | 220 | # Create a Network Security Group with some rules 221 | resource "azurerm_network_security_group" "main" { 222 | name = "${var.prefix}-nsg" 223 | location = "${azurerm_resource_group.main.location}" 224 | resource_group_name = "${azurerm_resource_group.main.name}" 225 | 226 | security_rule { 227 | name = "allow_SSH" 228 | description = "Allow SSH access" 229 | priority = 100 230 | direction = "Inbound" 231 | access = "Allow" 232 | protocol = "Tcp" 233 | source_port_range = "*" 234 | destination_port_range = "22" 235 | source_address_prefix = "*" 236 | destination_address_prefix = "*" 237 | } 238 | 239 | security_rule { 240 | name = "allow_HTTP" 241 | description = "Allow HTTP access" 242 | priority = 110 243 | direction = "Inbound" 244 | access = "Allow" 245 | protocol = "Tcp" 246 | source_port_range = "*" 247 | destination_port_range = "80" 248 | source_address_prefix = "*" 249 | destination_address_prefix = "*" 250 | } 251 | 252 | security_rule { 253 | name = "allow_HTTPS" 254 | description = "Allow HTTPS access" 255 | priority = 120 256 | direction = "Inbound" 257 | access = "Allow" 258 | protocol = "Tcp" 259 | source_port_range = "*" 260 | destination_port_range = "443" 261 | source_address_prefix = "*" 262 | destination_address_prefix = "*" 263 | } 264 | 265 | security_rule { 266 | name = "allow_RDP" 267 | description = "Allow RDP access" 268 | priority = 130 269 | direction = "Inbound" 270 | access = "Allow" 271 | protocol = "Tcp" 272 | source_port_range = "*" 273 | destination_port_range = "3389" 274 | source_address_prefix = "*" 275 | destination_address_prefix = "*" 276 | } 277 | 278 | security_rule { 279 | name = "allow_APP_HTTPS" 280 | description = "Allow HTTPS access" 281 | priority = 140 282 | direction = "Inbound" 283 | access = "Allow" 284 | protocol = "Tcp" 285 | source_port_range = "*" 286 | destination_port_range = "8443" 287 | source_address_prefix = "*" 288 | destination_address_prefix = "*" 289 | } 290 | 291 | tags { 292 | Name = "${var.environment}-bigip-sg" 293 | environment = "${var.environment}" 294 | owner = "${var.owner}" 295 | group = "${var.group}" 296 | costcenter = "${var.costcenter}" 297 | application = "${var.application}" 298 | } 299 | } 300 | 301 | # Create the first network interface card for Management 302 | resource "azurerm_network_interface" "vm01-mgmt-nic" { 303 | name = "${var.prefix}-vm01-mgmt-nic" 304 | location = "${azurerm_resource_group.main.location}" 305 | resource_group_name = "${azurerm_resource_group.main.name}" 306 | network_security_group_id = "${azurerm_network_security_group.main.id}" 307 | 308 | ip_configuration { 309 | name = "primary" 310 | subnet_id = "${azurerm_subnet.Mgmt.id}" 311 | private_ip_address_allocation = "Static" 312 | private_ip_address = "${var.f5vm01mgmt}" 313 | public_ip_address_id = "${azurerm_public_ip.vm01mgmtpip.id}" 314 | } 315 | 316 | tags { 317 | Name = "${var.environment}-vm01-mgmt-int" 318 | environment = "${var.environment}" 319 | owner = "${var.owner}" 320 | group = "${var.group}" 321 | costcenter = "${var.costcenter}" 322 | application = "${var.application}" 323 | } 324 | } 325 | 326 | resource "azurerm_network_interface" "vm02-mgmt-nic" { 327 | name = "${var.prefix}-vm02-mgmt-nic" 328 | location = "${azurerm_resource_group.main.location}" 329 | resource_group_name = "${azurerm_resource_group.main.name}" 330 | network_security_group_id = "${azurerm_network_security_group.main.id}" 331 | 332 | ip_configuration { 333 | name = "primary" 334 | subnet_id = "${azurerm_subnet.Mgmt.id}" 335 | private_ip_address_allocation = "Static" 336 | private_ip_address = "${var.f5vm02mgmt}" 337 | public_ip_address_id = "${azurerm_public_ip.vm02mgmtpip.id}" 338 | } 339 | 340 | tags { 341 | Name = "${var.environment}-vm02-mgmt-int" 342 | environment = "${var.environment}" 343 | owner = "${var.owner}" 344 | group = "${var.group}" 345 | costcenter = "${var.costcenter}" 346 | application = "${var.application}" 347 | } 348 | } 349 | 350 | # Create the second network interface card for External 351 | resource "azurerm_network_interface" "vm01-ext-nic" { 352 | name = "${var.prefix}-vm01-ext-nic" 353 | location = "${azurerm_resource_group.main.location}" 354 | resource_group_name = "${azurerm_resource_group.main.name}" 355 | network_security_group_id = "${azurerm_network_security_group.main.id}" 356 | depends_on = ["azurerm_lb_backend_address_pool.backend_pool"] 357 | 358 | ip_configuration { 359 | name = "primary" 360 | subnet_id = "${azurerm_subnet.External.id}" 361 | private_ip_address_allocation = "Static" 362 | private_ip_address = "${var.f5vm01ext}" 363 | primary = true 364 | } 365 | 366 | ip_configuration { 367 | name = "secondary" 368 | subnet_id = "${azurerm_subnet.External.id}" 369 | private_ip_address_allocation = "Static" 370 | private_ip_address = "${var.f5vm01ext_sec}" 371 | } 372 | 373 | tags { 374 | Name = "${var.environment}-vm01-ext-int" 375 | environment = "${var.environment}" 376 | owner = "${var.owner}" 377 | group = "${var.group}" 378 | costcenter = "${var.costcenter}" 379 | application = "${var.application}" 380 | } 381 | } 382 | 383 | resource "azurerm_network_interface" "vm02-ext-nic" { 384 | name = "${var.prefix}-vm02-ext-nic" 385 | location = "${azurerm_resource_group.main.location}" 386 | resource_group_name = "${azurerm_resource_group.main.name}" 387 | network_security_group_id = "${azurerm_network_security_group.main.id}" 388 | depends_on = ["azurerm_lb_backend_address_pool.backend_pool"] 389 | 390 | ip_configuration { 391 | name = "primary" 392 | subnet_id = "${azurerm_subnet.External.id}" 393 | private_ip_address_allocation = "Static" 394 | private_ip_address = "${var.f5vm02ext}" 395 | primary = true 396 | } 397 | 398 | ip_configuration { 399 | name = "secondary" 400 | subnet_id = "${azurerm_subnet.External.id}" 401 | private_ip_address_allocation = "Static" 402 | private_ip_address = "${var.f5vm02ext_sec}" 403 | } 404 | 405 | tags { 406 | Name = "${var.environment}-vm01-ext-int" 407 | environment = "${var.environment}" 408 | owner = "${var.owner}" 409 | group = "${var.group}" 410 | costcenter = "${var.costcenter}" 411 | application = "${var.application}" 412 | } 413 | } 414 | 415 | # Associate the Network Interface to the BackendPool 416 | resource "azurerm_network_interface_backend_address_pool_association" "bpool_assc_vm01" { 417 | network_interface_id = "${azurerm_network_interface.vm01-ext-nic.id}" 418 | ip_configuration_name = "secondary" 419 | backend_address_pool_id = "${azurerm_lb_backend_address_pool.backend_pool.id}" 420 | depends_on = ["azurerm_lb_backend_address_pool.backend_pool", "azurerm_network_interface.vm01-ext-nic"] 421 | } 422 | 423 | resource "azurerm_network_interface_backend_address_pool_association" "bpool_assc_vm02" { 424 | network_interface_id = "${azurerm_network_interface.vm02-ext-nic.id}" 425 | ip_configuration_name = "secondary" 426 | backend_address_pool_id = "${azurerm_lb_backend_address_pool.backend_pool.id}" 427 | depends_on = ["azurerm_lb_backend_address_pool.backend_pool", "azurerm_network_interface.vm02-ext-nic"] 428 | } 429 | 430 | # Setup Onboarding scripts 431 | data "template_file" "vm_onboard" { 432 | template = "${file("${path.module}/onboard.tpl")}" 433 | 434 | vars { 435 | uname = "${var.uname}" 436 | upassword = "${var.upassword}" 437 | DO_onboard_URL = "${var.DO_onboard_URL}" 438 | AS3_URL = "${var.AS3_URL}" 439 | libs_dir = "${var.libs_dir}" 440 | onboard_log = "${var.onboard_log}" 441 | } 442 | } 443 | 444 | data "template_file" "vm01_do_json" { 445 | template = "${file("${path.module}/cluster.json")}" 446 | 447 | vars { 448 | #Uncomment the following line for BYOL 449 | #local_sku = "${var.license1}" 450 | 451 | host1 = "${var.host1_name}" 452 | host2 = "${var.host2_name}" 453 | local_host = "${var.host1_name}" 454 | local_selfip = "${var.f5vm01ext}" 455 | remote_host = "${var.host2_name}" 456 | remote_selfip = "${var.f5vm02ext}" 457 | gateway = "${local.ext_gw}" 458 | dns_server = "${var.dns_server}" 459 | ntp_server = "${var.ntp_server}" 460 | timezone = "${var.timezone}" 461 | admin_user = "${var.uname}" 462 | admin_password = "${var.upassword}" 463 | } 464 | } 465 | 466 | data "template_file" "vm02_do_json" { 467 | template = "${file("${path.module}/cluster.json")}" 468 | 469 | vars { 470 | #Uncomment the following line for BYOL 471 | #local_sku = "${var.license2}" 472 | 473 | host1 = "${var.host1_name}" 474 | host2 = "${var.host2_name}" 475 | local_host = "${var.host2_name}" 476 | local_selfip = "${var.f5vm02ext}" 477 | remote_host = "${var.host1_name}" 478 | remote_selfip = "${var.f5vm01ext}" 479 | gateway = "${local.ext_gw}" 480 | dns_server = "${var.dns_server}" 481 | ntp_server = "${var.ntp_server}" 482 | timezone = "${var.timezone}" 483 | admin_user = "${var.uname}" 484 | admin_password = "${var.upassword}" 485 | } 486 | } 487 | 488 | data "template_file" "as3_json" { 489 | template = "${file("${path.module}/as3.json")}" 490 | } 491 | 492 | # Create F5 BIGIP VMs 493 | resource "azurerm_virtual_machine" "f5vm01" { 494 | name = "${var.prefix}-f5vm01" 495 | location = "${azurerm_resource_group.main.location}" 496 | resource_group_name = "${azurerm_resource_group.main.name}" 497 | primary_network_interface_id = "${azurerm_network_interface.vm01-mgmt-nic.id}" 498 | network_interface_ids = ["${azurerm_network_interface.vm01-mgmt-nic.id}", "${azurerm_network_interface.vm01-ext-nic.id}"] 499 | vm_size = "${var.instance_type}" 500 | availability_set_id = "${azurerm_availability_set.avset.id}" 501 | 502 | # Uncomment this line to delete the OS disk automatically when deleting the VM 503 | # delete_os_disk_on_termination = true 504 | 505 | 506 | # Uncomment this line to delete the data disks automatically when deleting the VM 507 | # delete_data_disks_on_termination = true 508 | 509 | storage_image_reference { 510 | publisher = "f5-networks" 511 | offer = "${var.product}" 512 | sku = "${var.image_name}" 513 | version = "${var.bigip_version}" 514 | } 515 | 516 | storage_os_disk { 517 | name = "${var.prefix}vm01-osdisk" 518 | caching = "ReadWrite" 519 | create_option = "FromImage" 520 | managed_disk_type = "Standard_LRS" 521 | } 522 | 523 | os_profile { 524 | computer_name = "${var.prefix}vm01" 525 | admin_username = "${var.uname}" 526 | admin_password = "${var.upassword}" 527 | custom_data = "${data.template_file.vm_onboard.rendered}" 528 | } 529 | 530 | os_profile_linux_config { 531 | disable_password_authentication = false 532 | } 533 | 534 | plan { 535 | name = "${var.image_name}" 536 | publisher = "f5-networks" 537 | product = "${var.product}" 538 | } 539 | 540 | tags { 541 | Name = "${var.environment}-f5vm01" 542 | environment = "${var.environment}" 543 | owner = "${var.owner}" 544 | group = "${var.group}" 545 | costcenter = "${var.costcenter}" 546 | application = "${var.application}" 547 | } 548 | 549 | provisioner "file" { 550 | content = "${data.template_file.vm01_do_json.rendered}" 551 | destination = "/var/tmp/vm_do.json" 552 | connection { 553 | user = "${var.uname}" 554 | password = "${var.upassword}" 555 | agent = false 556 | } 557 | } 558 | 559 | provisioner "file" { 560 | content = "${data.template_file.as3_json.rendered}" 561 | destination = "/var/tmp/as3.json" 562 | connection { 563 | user = "${var.uname}" 564 | password = "${var.upassword}" 565 | agent = false 566 | } 567 | } 568 | } 569 | 570 | resource "azurerm_virtual_machine" "f5vm02" { 571 | name = "${var.prefix}-f5vm02" 572 | location = "${azurerm_resource_group.main.location}" 573 | resource_group_name = "${azurerm_resource_group.main.name}" 574 | primary_network_interface_id = "${azurerm_network_interface.vm02-mgmt-nic.id}" 575 | network_interface_ids = ["${azurerm_network_interface.vm02-mgmt-nic.id}", "${azurerm_network_interface.vm02-ext-nic.id}"] 576 | vm_size = "${var.instance_type}" 577 | availability_set_id = "${azurerm_availability_set.avset.id}" 578 | 579 | # Uncomment this line to delete the OS disk automatically when deleting the VM 580 | # delete_os_disk_on_termination = true 581 | 582 | 583 | # Uncomment this line to delete the data disks automatically when deleting the VM 584 | # delete_data_disks_on_termination = true 585 | 586 | storage_image_reference { 587 | publisher = "f5-networks" 588 | offer = "${var.product}" 589 | sku = "${var.image_name}" 590 | version = "${var.bigip_version}" 591 | } 592 | 593 | storage_os_disk { 594 | name = "${var.prefix}vm02-osdisk" 595 | caching = "ReadWrite" 596 | create_option = "FromImage" 597 | managed_disk_type = "Standard_LRS" 598 | } 599 | 600 | os_profile { 601 | computer_name = "${var.prefix}vm02" 602 | admin_username = "${var.uname}" 603 | admin_password = "${var.upassword}" 604 | custom_data = "${data.template_file.vm_onboard.rendered}" 605 | } 606 | 607 | os_profile_linux_config { 608 | disable_password_authentication = false 609 | } 610 | 611 | plan { 612 | name = "${var.image_name}" 613 | publisher = "f5-networks" 614 | product = "${var.product}" 615 | } 616 | 617 | tags { 618 | Name = "${var.environment}-f5vm02" 619 | environment = "${var.environment}" 620 | owner = "${var.owner}" 621 | group = "${var.group}" 622 | costcenter = "${var.costcenter}" 623 | application = "${var.application}" 624 | } 625 | 626 | provisioner "file" { 627 | content = "${data.template_file.vm02_do_json.rendered}" 628 | destination = "/var/tmp/vm_do.json" 629 | connection { 630 | user = "${var.uname}" 631 | password = "${var.upassword}" 632 | agent = false 633 | } 634 | } 635 | 636 | provisioner "file" { 637 | content = "${data.template_file.as3_json.rendered}" 638 | destination = "/var/tmp/as3.json" 639 | connection { 640 | user = "${var.uname}" 641 | password = "${var.upassword}" 642 | agent = false 643 | } 644 | } 645 | } 646 | 647 | 648 | # Run Startup Script 649 | resource "azurerm_virtual_machine_extension" "f5vm01-run-startup-cmd" { 650 | name = "${var.environment}-f5vm01-run-startup-cmd" 651 | location = "${var.region}" 652 | resource_group_name = "${azurerm_resource_group.main.name}" 653 | virtual_machine_name = "${azurerm_virtual_machine.f5vm01.name}" 654 | publisher = "Microsoft.OSTCExtensions" 655 | type = "CustomScriptForLinux" 656 | type_handler_version = "1.2" 657 | depends_on = ["azurerm_virtual_machine.f5vm01"] 658 | # publisher = "Microsoft.Azure.Extensions" 659 | # type = "CustomScript" 660 | # type_handler_version = "2.0" 661 | 662 | settings = <>$LOG_FILE 11 | else 12 | #if file exists, exit as only want to run once 13 | exit 14 | fi 15 | 16 | exec 1>$LOG_FILE 2>&1 17 | 18 | # CHECK TO SEE NETWORK IS READY 19 | CNT=0 20 | while true 21 | do 22 | STATUS=$(curl -s -k -I example.com | grep HTTP) 23 | if [[ $STATUS == *"200"* ]]; then 24 | echo "Got 200! VE is Ready!" 25 | break 26 | elif [ $CNT -le 6 ]; then 27 | echo "Status code: $STATUS Not done yet..." 28 | CNT=$[$CNT+1] 29 | else 30 | echo "GIVE UP..." 31 | break 32 | fi 33 | sleep 10 34 | done 35 | 36 | ### DOWNLOAD ONBOARDING PKGS 37 | # Could be pre-packaged or hosted internally 38 | 39 | admin_username='${uname}' 40 | admin_password='${upassword}' 41 | CREDS="admin:"$admin_password 42 | DO_URL='${DO_onboard_URL}' 43 | DO_FN=$(basename "$DO_URL") 44 | AS3_URL='${AS3_URL}' 45 | AS3_FN=$(basename "$AS3_URL") 46 | 47 | mkdir -p ${libs_dir} 48 | 49 | echo -e "\n"$(date) "Download Declarative Onboarding Pkg" 50 | curl -o -L ${libs_dir}/$DO_FN $DO_URL 51 | 52 | echo -e "\n"$(date) "Download AS3 Pkg" 53 | curl -o -L ${libs_dir}/$AS3_FN $AS3_URL 54 | sleep 20 55 | 56 | # Copy the RPM Pkg to the file location 57 | cp ${libs_dir}/*.rpm /var/config/rest/downloads/ 58 | 59 | # Install Declarative Onboarding Pkg 60 | DATA="{\"operation\":\"INSTALL\",\"packageFilePath\":\"/var/config/rest/downloads/$DO_FN\"}" 61 | echo -e "\n"$(date) "Install DO Pkg" 62 | curl -u $CREDS -X POST http://localhost:8100/mgmt/shared/iapp/package-management-tasks -d $DATA 63 | 64 | # Install AS3 Pkg 65 | DATA="{\"operation\":\"INSTALL\",\"packageFilePath\":\"/var/config/rest/downloads/$AS3_FN\"}" 66 | echo -e "\n"$(date) "Install AS3 Pkg" 67 | curl -u $CREDS -X POST http://localhost:8100/mgmt/shared/iapp/package-management-tasks -d $DATA 68 | 69 | sleep 5 70 | 71 | echo -e "\n"$(date) "Setup Cluster With Declarative Onboarding" 72 | curl -k -u $CREDS -X POST https://localhost/mgmt/shared/declarative-onboarding -d @/var/tmp/vm_do.json 73 | 74 | echo -e "\n"$(date) "Configure HTTPS/HTTP Virtual with AS3" 75 | curl -k -u $CREDS -X POST https://localhost/mgmt/shared/appsvcs/declare -d @/var/tmp/as3.json 76 | -------------------------------------------------------------------------------- /Azure_DMZ_To_Onprem/provider.tf: -------------------------------------------------------------------------------- 1 | # Configure the Microsoft Azure Provider, replace Service Principal and Subscription with your own 2 | provider "azurerm" { 3 | subscription_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 4 | client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 5 | client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 6 | tenant_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 7 | } 8 | 9 | -------------------------------------------------------------------------------- /Azure_DMZ_To_Onprem/variables.tf: -------------------------------------------------------------------------------- 1 | # Environment 2 | variable prefix { default = "zlupdmz" } 3 | variable uname { default = "azureuser" } 4 | variable upassword { default = "Default12345" } 5 | variable location { default = "eastus" } 6 | variable region { default = "East US" } 7 | 8 | # NETWORK 9 | variable "onpremsite1" { 10 | type = "map" 11 | default = { 12 | "publicip" = "128.8.8.8" 13 | "addrspace1" = "10.101.1.0/24" 14 | "addrspace2" = "10.101.0.0/24" 15 | "sharekey" = "abc123" 16 | } 17 | } 18 | variable cidr { default = "10.90.0.0/16" } 19 | variable "subnets" { 20 | type = "map" 21 | default = { 22 | "gwsubnet" = "10.90.255.0/24" 23 | "subnet1" = "10.90.1.0/24" 24 | "subnet2" = "10.90.2.0/24" 25 | "subnet3" = "10.90.3.0/24" 26 | } 27 | } 28 | variable f5vm01mgmt { default = "10.90.1.4" } 29 | variable f5vm01ext { default = "10.90.2.4" } 30 | variable f5vm01ext_sec { default = "10.90.2.11" } 31 | variable f5vm02mgmt { default = "10.90.1.5" } 32 | variable f5vm02ext { default = "10.90.2.5" } 33 | variable f5vm02ext_sec { default = "10.90.2.12" } 34 | variable lb_ip { default = "10.90.2.100" } 35 | 36 | # BIGIP Image 37 | variable instance_type { default = "Standard_D3_v2" } 38 | variable image_name { default = "f5-bigip-virtual-edition-25m-best-hourly" } 39 | variable product { default = "f5-big-ip-best" } 40 | variable bigip_version { default = "latest" } 41 | 42 | # BIGIP Setup 43 | variable license1 { default = ""} 44 | variable license2 { default = ""} 45 | variable host1_name { default = "f5vm01"} 46 | variable host2_name { default = "f5vm02"} 47 | variable dns_server { default = "8.8.8.8" } 48 | variable ntp_server { default = "0.us.pool.ntp.org" } 49 | variable timezone { default = "UTC" } 50 | ## Please check and update the latest DO URL from https://github.com/F5Networks/f5-declarative-onboarding/releases 51 | variable DO_onboard_URL { default = "https://raw.githubusercontent.com/F5Networks/f5-declarative-onboarding/master/dist/f5-declarative-onboarding-1.3.0-4.noarch.rpm" } 52 | ## Please check and update the latest AS3 URL from https://github.com/F5Networks/f5-appsvcs-extension/releases/latest 53 | variable AS3_URL { default = "https://raw.githubusercontent.com/F5Networks/f5-appsvcs-extension/master/dist/latest/f5-appsvcs-3.9.0-3.noarch.rpm" } 54 | variable libs_dir { default = "/config/cloud/azure/node_modules" } 55 | variable onboard_log { default = "/var/log/startup-script.log" } 56 | 57 | # TAGS 58 | variable purpose { default = "public" } 59 | variable environment { default = "f5env" } #ex. dev/staging/prod 60 | variable owner { default = "f5owner" } 61 | variable group { default = "f5group" } 62 | variable costcenter { default = "f5costcenter" } 63 | variable application { default = "f5app" } 64 | 65 | -------------------------------------------------------------------------------- /Azure_Secure_Enclave_Public_DMZ/README.md: -------------------------------------------------------------------------------- 1 | # F5 Secure Enclave for Azure Public DMZ 2 | 3 | ## Contents 4 | 5 | - [Version](#version) 6 | - [Introduction](#introduction) 7 | - [Prerequisites](#prerequisites) 8 | - [Important Configuration Notes](#important-configuration-notes) 9 | - [Template Parameters](#Template-parameters) 10 | - [Configuration Example](#configuration-example) 11 | 12 | ## Version 13 | This template is tested and worked in the following version 14 | Terraform v0.12.6 15 | + provider.azurerm v1.36.1 16 | + provider.local v1.4.0 17 | + provider.null v2.1.2 18 | + provider.template v2.1.2 19 | 20 | ## Introduction 21 | 22 | This solution uses an Terraform template to launch a Four NICs deployment of a cloud-focused BIG-IP VE cluster (Active/Standby) in Microsoft Azure. Traffic flows from an ALB to the BIG-IP VE which then processes the traffic to application servers. This is the standard cloud design where the BIG-IP VE instance is running with Two interfaces: Management and External. 23 | 24 | The BIG-IP VEs have the [Local Traffic Manager (LTM)](https://f5.com/products/big-ip/local-traffic-manager-ltm) module and [Application_Security_Module (ASM)](https://www.f5.com/pdf/products/big-ip-application-security-manager-overview.pdf) enabled to provide advanced traffic management functionality. This means you can also configure the BIG-IP VE to enable F5's L4/L7 security features, access control, and intelligent traffic management. The suggested SKU is F5-BIG-LTM-VE-1G-V16 base SKU, so we can also enable WAF and Telemetry Streaming for future developments 25 | 26 | The one big thing in this Terraform accounted for is composing resources a bit differently to account for dependencies into Immutable/Mutable elements. i.e. stuff you would typically frequently change/mutate, such as traditional config on the BIG-IP. Once the template is deployed, there are certain resources (like the network infrastructure) that are fixed while others (like BIG-IP VMs and configurations) can be changed 27 | Ex. 28 | -> Run once 29 | - Deploy the entire infrastructure with all the neccessary resources, then we use Declarative Onboarding to configure the BIG-IP Cluster; AS3 to create a sample app proxy; then lastly use Service Discovery automatically add the DVWA container app to the LTM pool (Please note currently we also hardcode the node IP in the pool due to a bug in our AS3, which will be fixed in the next release) 30 | 31 | -> Run many X 32 | - [Redeploy BIG-IP for replacement or upgrade](#Redeploy-BIG-IP-for-replacement-or-upgrade) 33 | - [Reconfigure BIG-IP configurations](#Rerun-AS3-on-the-big-ip-ve) 34 | 35 | **Networking Stack Type:** This solution deploys into a new networking stack, which is created along with the solution. 36 | 37 | ## Prerequisites 38 | 39 | - **Important**: When you configure the admin password for the BIG-IP VE in the template, you cannot use the character **#**. Additionally, there are a number of other special characters that you should avoid using for F5 product user accounts. See [K2873](https://support.f5.com/csp/article/K2873) for details. 40 | - This template requires a service principal. See the [Service Principal Setup section](#service-principal-authentication) for details, including required permissions. 41 | - This deployment will be using the Terraform Azurerm provider to build out all the neccessary Azure objects. Therefore, Azure CLI is required. for installation, please follow this [Microsoft link](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-apt?view=azure-cli-latest) 42 | - If this is the first time to deploy the F5 image, the subscription used in this deployment needs to be enabled to programatically deploy. For more information, please refer to [Configure Programatic Deployment](https://azure.microsoft.com/en-us/blog/working-with-marketplace-images-on-azure-resource-manager/) 43 | 44 | ## Important configuration notes 45 | 46 | - All variables are configured in variables.tf 47 | - Azure Subscription and Service Principal are configured in provider.tf 48 | - This template would require Declarative Onboarding and AS3 packages for the initial configuration. As part of the onboarding script, it will download the RPMs respectively. So please see the [AS3 documentation](https://clouddocs.f5.com/products/extensions/f5-appsvcs-extension/latest/) and [DO documentation](https://clouddocs.f5.com/products/extensions/f5-declarative-onboarding/latest/prereqs.html) for details on how to use AS3 and Declarative Onboarding on your BIG-IP VE(s). 49 | - onboard.tpl is the onboarding script, which is run by commandToExecute, and it will be copy to /var/lib/waagent/CustomData upon bootup. This script is basically responsible for downloading the neccessary DO, AS3, and TS RPM files, and then installing them with REST calls. 50 | - This template uses BYOL BIGIP image for the deployment (as default) 51 | - The initial deployment will enable you to pass traffic from your clients to the DVWA app server. See [Rerun AS3](#Rerun-AS3-on-the-big-ip-ve) if you would like to reconfigure the AS3 configuration. 52 | - See the **[Configuration Example](#configuration-example)** section for a configuration diagram and description for this solution. 53 | 54 | ### Template parameters 55 | 56 | | Parameter | Required | Description | 57 | | --- | --- | --- | 58 | | prefix | Yes | This value is insert in the beginning of each Azure object, try keeps it alpha-numeric without any special character | 59 | | rest_do_uri | Yes | URI of the Declarative Onboarding REST call. | 60 | | rest_as3_uri | Yes | URI of the AS3 REST call. | 61 | | rest_do_method | Yes | Available options are GET, POST, and DELETE. | 62 | | rest_AS3_method | Yes | Available options are GET, POST, and DELETE. | 63 | | rest_vm01_do_file | Yes | Terraform will generate the vm01 DO json file, where you can manually run it again for debugging. | 64 | | rest_vm02_do_file | Yes | Terraform will generate the vm02 DO json file, where you can manually run it again for debugging. | 65 | | rest_vm_as3_file | Yes | Terraform will generate the AS3 json file, where you can manually run it again for debugging. | 66 | | SP | YES | This is the service principal of your Azure subscription. | 67 | | uname | Yes | User name for the Virtual Machine. | 68 | | upassword | Yes | Password for the Virtual Machine. | 69 | | location | Yes | Location of the deployment. | 70 | | region | Yes | Region of the deployment. | 71 | | cidr | Yes | IP Address range of the DMZ Virtual Network, which contains 'subnet1' for mgmt network, 'subnet2' for external network, and 'subnet3' for internal network. | 72 | | app-cidr | Yes | IP Address range of the App Network, which is sitting at another VNet and being peered to the DMZ Vnet. | 73 | | f5vm01mgmt | Yes | IP address for 1st BIG-IP's management interface. | 74 | | f5vm02mgmt | Yes | IP address for 2nd BIG-IP's management interface. | 75 | | f5vm01ext | Yes | IP address for 1st BIG-IP's external interface. | 76 | | f5vm02ext | Yes | IP address for 2nd BIG-IP's external interface. | 77 | | instance_type | Yes | Azure instance to be used for the BIG-IP VE. | 78 | | product | Yes | Azure BIG-IP VE Offer. | 79 | | bigip_version | Yes | It is set to default to use the latest software. | 80 | | image_name | Yes | F5 SKU (image) to you want to deploy. Note: The disk size of the VM will be determined based on the option you select. **Important**: If intending to provision multiple modules, ensure the appropriate value is selected, such as ****AllTwoBootLocations or AllOneBootLocation****. | 81 | | license1 | No | The license token for the F5 BIG-IP VE (BYOL). | 82 | | license2 | No | The license token for the F5 BIG-IP VE (BYOL). | 83 | | host1_name | Yes | Hostname for the 1st BIG-IP. | 84 | | host2_name | Yes | Hostname for the 2nd BIG-IP. | 85 | | ntp_server | Yes | Leave the default NTP server the BIG-IP uses, or replace the default NTP server with the one you want to use. | 86 | | timezone | Yes | If you would like to change the time zone the BIG-IP uses, enter the time zone you want to use. This is based on the tz database found in /usr/share/zoneinfo (see the full list [here](https://github.com/F5Networks/f5-azure-arm-templates/blob/master/azure-timezone-list.md)). Example values: UTC, US/Pacific, US/Eastern, Europe/London or Asia/Singapore. | 87 | | dns_server | Yes | Least the default DNS server the BIG-IP uses, or replace the default DNS server with the one you want to use. | 88 | | DO_onboard_URL | Yes | This is the raw github URL for downloading the Declarative Onboarding RPM | 89 | | AS3_URL | Yes | This is the raw github URL for downloading the AS3 RPM. | 90 | | TS_URL | Yes | This is the raw github URL for downloading the Telemetry Streaming RPM. | 91 | | libs_dir | Yes | This is where all the temporary libs and RPM will be store in BIG-IP. | 92 | | onboard_log | Yes | This is where the onboarding script logs all the events. | 93 | 94 | 95 | ## Configuration Example 96 | 97 | The following is an example configuration diagram for this solution deployment. In this scenario, all access to the BIG-IP VE cluster (Active/Standby) is through an ALB. The IP addresses in this example may be different in your implementation. 98 | 99 | ![Configuration Example](./Secure_Enclave_public_dmz.png) 100 | 101 | 102 | ## Azure Sentinel integration 103 | 104 | This deployment has created an Azure Log Analytic Workspace, and F5 BIG-IP would push the LTM and ASM logs via Telemetry Streaming to the Analytic Workspace. In other words, all the ASM and LTM logs are ready to be used for the Azure Sentinel Workbook. Please refer to the following screenshots. 105 | 106 | 107 | 108 | 109 | 110 | ## Documentation 111 | 112 | For more information on F5 solutions for Azure, including manual configuration procedures for some deployment scenarios, see the Azure section of [Public Cloud Docs](http://clouddocs.f5.com/cloud/public/v1/). 113 | 114 | For more information on F5 and Sentinel Integration, please refer to [F5 Devcentral link](https://devcentral.f5.com/s/articles/Integrating-the-F5-BIGIP-with-Azure-Sentinel) 115 | 116 | 117 | ## Redeploy BIG-IP for replacement or upgrade 118 | This example illustrates how to replace the BIG-IP VE 119 | 1. Revoke the problematic BIG-IP VE's license 120 | 2. Run command 121 | ``` 122 | terraform destroy -target azurerm_virtual_machine.f5vm02 123 | ``` 124 | 3. Run command 125 | ``` 126 | terraform apply 127 | ``` 128 | 4. You have 2 Active/Standby BIG-IP VEs behind the Azure LB. Repeate step 1 to step 3 on the other BIG-IP VE and HA Device Trust should be configured 129 | 130 | 131 | This example illustrate how to upgrade the BIG-IP VEs (remember, when replace a VE, we replace both, can't be just single VE) 132 | 1. Change the 'bigip_version' variable to the desired release 133 | 2. Revoke the problematic BIG-IP VE's license 134 | 3. Run command 135 | ``` 136 | terraform destroy -target azurerm_virtual_machine.f5vm02 137 | ``` 138 | 4. Run command 139 | ``` 140 | terraform apply 141 | ``` 142 | 5. You have 2 Active/Standby BIG-IP VEs behind the Azure LB. Repeate step 1 to step 3 on the other BIG-IP VE and HA Device Trust should be configured 143 | 144 | ## Rerun AS3 on the Big-ip ve 145 | - This example illustrate how to run your own custom AS3, you can have a catalog of AS3 and repeat this steps as many times as desired 146 | ``` 147 | terraform taint null_resource.f5vm_AS3 148 | terraform apply -target null_resource.f5vm_AS3 149 | ``` 150 | - If you would like to re-run your DO json, just swap the above REST methods, and apply the new DO json file, then you can repeat the above steps as many time as you'd need. 151 | -------------------------------------------------------------------------------- /Azure_Secure_Enclave_Public_DMZ/Secure_Enclave_public_dmz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garyluf5/f5_terraform/ab4ceb4c754d507d4db96b30cbb75ac53e30d61f/Azure_Secure_Enclave_Public_DMZ/Secure_Enclave_public_dmz.png -------------------------------------------------------------------------------- /Azure_Secure_Enclave_Public_DMZ/as3.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "AS3", 3 | "action": "deploy", 4 | "persist": true, 5 | "declaration": { 6 | "class": "ADC", 7 | "schemaVersion": "3.13.0", 8 | "id": "123abc", 9 | "label": "Sample 1", 10 | "remark": "HTTPS with predictive-node pool", 11 | "Sample_01": { 12 | "class": "Tenant", 13 | "A1": { 14 | "class": "Application", 15 | "template": "https", 16 | "serviceMain": { 17 | "class": "Service_HTTPS", 18 | "virtualPort": 8443, 19 | "virtualAddresses": [ 20 | "0.0.0.0" 21 | ], 22 | "securityLogProfiles": [ 23 | { 24 | "bigip": "/Common/Log all requests" 25 | }, 26 | { 27 | "use": "telemetry_security_log_profile" 28 | } 29 | ], 30 | "snat": "auto", 31 | "pool": "web_pool", 32 | "policyWAF": { 33 | "use": "My_ASM_Policy" 34 | }, 35 | "serverTLS": "webtls", 36 | "profileTrafficLog": { 37 | "use": "telemetry_traffic_log_profile" 38 | } 39 | }, 40 | "My_ASM_Policy": { 41 | "class": "WAF_Policy", 42 | "url": "https://raw.githubusercontent.com/garyluf5/f5tools/master/asm-policies/asm-policy-linux-medium.xml", 43 | "ignoreChanges": true 44 | }, 45 | "web_pool": { 46 | "class": "Pool", 47 | "monitors": [ 48 | "tcp" 49 | ], 50 | "members": [ 51 | { 52 | "servicePort": 80, 53 | "serverAddresses": [ 54 | "${backendvm_ip}" 55 | ] 56 | } 57 | ] 58 | }, 59 | "telemetry": { 60 | "class": "Pool", 61 | "members": [ 62 | { 63 | "enable": true, 64 | "serverAddresses": [ 65 | "255.255.255.254" 66 | ], 67 | "servicePort": 6514 68 | } 69 | ], 70 | "monitors": [ 71 | { 72 | "bigip": "/Common/tcp" 73 | } 74 | ] 75 | }, 76 | "telemetry_local_pool": { 77 | "class": "Pool", 78 | "monitors": [{ 79 | "bigip": "/Common/tcp" 80 | }], 81 | "members": [ 82 | { 83 | "servicePort": 6514, 84 | "serverAddresses": [ 85 | "255.255.255.254" 86 | ] 87 | } 88 | ] 89 | }, 90 | "telemetry_local_rule": { 91 | "remark": "Only required when TS is a local listener", 92 | "class": "iRule", 93 | "iRule": "when CLIENT_ACCEPTED {\n node 127.0.0.1 6514\n}" 94 | }, 95 | "telemetry_local": { 96 | "remark": "Only required when TS is a local listener", 97 | "class": "Service_TCP", 98 | "virtualAddresses": [ 99 | "255.255.255.254" 100 | ], 101 | "virtualPort": 6514, 102 | "iRules": [ 103 | "telemetry_local_rule" 104 | ] 105 | }, 106 | "telemetry_hsl": { 107 | "class": "Log_Destination", 108 | "type": "remote-high-speed-log", 109 | "protocol": "tcp", 110 | "pool": { 111 | "use": "telemetry" 112 | } 113 | }, 114 | "telemetry_formatted": { 115 | "class": "Log_Destination", 116 | "type": "splunk", 117 | "forwardTo": { 118 | "use": "telemetry_hsl" 119 | } 120 | }, 121 | "telemetry_publisher": { 122 | "class": "Log_Publisher", 123 | "destinations": [ 124 | { 125 | "use": "telemetry_formatted" 126 | } 127 | ] 128 | }, 129 | "telemetry_traffic_log_profile": { 130 | "class": "Traffic_Log_Profile", 131 | "requestSettings": { 132 | "requestEnabled": true, 133 | "requestProtocol": "mds-tcp", 134 | "requestPool": { 135 | "use": "telemetry_local_pool" 136 | }, 137 | "requestTemplate": "event_source=\"request_logging\",hostname=\"$BIGIP_HOSTNAME\",client_ip=\"$CLIENT_IP\",server_ip=\"$SERVER_IP\",http_method=\"$HTTP_METHOD\",http_uri=\"$HTTP_URI\",virtual_name=\"$VIRTUAL_NAME\",event_timestamp=\"$DATE_HTTP\"" 138 | } 139 | }, 140 | "telemetry_security_log_profile": { 141 | "class": "Security_Log_Profile", 142 | "application": { 143 | "localStorage": false, 144 | "remoteStorage": "splunk", 145 | "protocol": "tcp", 146 | "servers": [ 147 | { 148 | "address": "255.255.255.254", 149 | "port": "6514" 150 | } 151 | ], 152 | "storageFilter": { 153 | "requestType": "all" 154 | } 155 | } 156 | }, 157 | "webtls": { 158 | "class": "TLS_Server", 159 | "certificates": [{ 160 | "certificate": "webcert" 161 | }] 162 | }, 163 | "webcert": { 164 | "class": "Certificate", 165 | "remark": "in practice we recommend using a passphrase", 166 | "certificate": "-----BEGIN CERTIFICATE-----\nMIICnDCCAgWgAwIBAgIJAJ5n2b0OCEjwMA0GCSqGSIb3DQEBCwUAMGcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMRQwEgYDVQQKDAtmNV9OZXR3b3JrczEbMBkGA1UEAwwSc2FtcGxlLmV4YW1wbGUubmV0MB4XDTE3MTEyNjE5NTAyNFoXDTE4MDIyNTE5NTAyNFowZzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxFDASBgNVBAoMC2Y1X05ldHdvcmtzMRswGQYDVQQDDBJzYW1wbGUuZXhhbXBsZS5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALEsuXmSXVQpYjrZPW+WiTBjn491mwZYT7Q92V1HlSBtM6WdWlK1aZN5sovfKtOX7Yrm8xa+e4o/zJ2QYLyyv5O+t2EGN/4qUEjEAPY9mwJdfzRQy6Hyzm84J0QkTuUJ/EjNuPji3D0QJRALUTzu1UqqDCEtiN9OGyXEkh7uvb7BAgMBAAGjUDBOMB0GA1UdDgQWBBSVHPNrGWrjWyZvckQxFYWO59FRFjAfBgNVHSMEGDAWgBSVHPNrGWrjWyZvckQxFYWO59FRFjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBAJeJ9SEckEwPhkXOm+IuqfbUS/RcziifBCTmVyE+Fa/j9pKSYTgiEBNdbJeBEa+gPMlQtbV7Y2dy8TKx/8axVBHiXC5geDML7caxOrAyHYBpnx690xJTh5OIORBBM/a/NvaR+P3CoVebr/NPRh9oRNxnntnqvqD7SW0U3ZPe3tJc\n-----END CERTIFICATE-----", 167 | "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-256-CBC,D8FFCE6B255601587CB54EC29B737D31\n\nkv4Fc3Jn0Ujkj0yRjt+gQQfBLSNF2aRLUENXnlr7Xpzqu0Ahr3jS1bAAnd8IWnsR\nyILqVmKsYF2DoHh0tWiEAQ7/y/fe5DTFhK7N4Wml6kp2yVMkP6KC4ssyYPw27kjK\nDBwBZ5O8Ioej08A5sgsLCmglbmtSPHJUn14pQnMTmLOpEtOsu6S+2ibPgSNpdg0b\nCAJNG/KHe+Vkx59qNDyDeKb7FZOlsX30+y67zUq9GQqJEDuysPJ2BUNP0IJXAjst\nFIt1qNoZew+5KDYs7u/lPxcMGTirUhgI84Jy4WcDvSOsP/tKlxj04TbIE3epmSKy\n+TihHkwY7ngIGtcm3Sfqk5jz2RXoj1/Ac3SW8kVTYaOUogBhn7zAq4Wju6Et4hQG\nRGapsJp1aCeZ/a4RCDTxspcKoMaRa97/URQb0hBRGx3DGUhzpmX9zl7JI2Xa5D3R\nmdBXtjLKYJTdIMdd27prBEKhMUpae2rz5Mw4J907wZeBq/wu+zp8LAnecfTe2nGY\nE32x1U7gSEdYOGqnwxsOexb1jKgCa67Nw9TmcMPV8zmH7R9qdvgxAbAtwBl1F9OS\nfcGaC7epf1AjJLtaX7krWmzgASHl28Ynh9lmGMdv+5QYMZvKG0LOg/n3m8uJ6sKy\nIzzvaJswwn0j5P5+czyoV5CvvdCfKnNb+3jUEN8I0PPwjBGKr4B1ojwhogTM248V\nHR69D6TxFVMfGpyJhCPkbGEGbpEpcffpgKuC/mEtMqyDQXJNaV5HO6HgAJ9F1P6v\n5ehHHTMRvzCCFiwndHdlMXUjqSNjww6me6dr6LiAPbejdzhL2vWx1YqebOcwQx3G\n-----END RSA PRIVATE KEY-----", 168 | "passphrase": { 169 | "ciphertext": "ZjVmNQ==", 170 | "protected": "eyJhbGciOiJkaXIiLCJlbmMiOiJub25lIn0" 171 | } 172 | } 173 | } 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /Azure_Secure_Enclave_Public_DMZ/cluster.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0.0", 3 | "class": "Device", 4 | "async": true, 5 | "label": "Basic onboarding", 6 | "Common": { 7 | "class": "Tenant", 8 | "hostname": "${local_host}.example.com", 9 | "myLicense": { 10 | "class": "License", 11 | "licenseType": "regKey", 12 | "regKey": "${regkey}" 13 | }, 14 | "dbvars": { 15 | "class": "DbVariables", 16 | "ui.advisory.enabled": true, 17 | "ui.advisory.color": "green", 18 | "ui.advisory.text": "/Common/hostname" 19 | }, 20 | "myDns": { 21 | "class": "DNS", 22 | "nameServers": [ 23 | "${dns_server}", 24 | "2001:4860:4860::8844" 25 | ], 26 | "search": [ 27 | "f5.com" 28 | ] 29 | }, 30 | "myNtp": { 31 | "class": "NTP", 32 | "servers": [ 33 | "${ntp_server}", 34 | "0.pool.ntp.org", 35 | "1.pool.ntp.org" 36 | ], 37 | "timezone": "${timezone}" 38 | }, 39 | "myProvisioning": { 40 | "class": "Provision", 41 | "ltm": "nominal", 42 | "asm": "nominal" 43 | }, 44 | "external": { 45 | "class": "VLAN", 46 | "tag": 1000, 47 | "mtu": 1500, 48 | "interfaces": [ 49 | { 50 | "name": "1.1", 51 | "tagged": false 52 | } 53 | ] 54 | }, 55 | "external-self": { 56 | "class": "SelfIp", 57 | "address": "${local_selfip1}/24", 58 | "vlan": "external", 59 | "allowService": "default", 60 | "trafficGroup": "traffic-group-local-only" 61 | }, 62 | "default": { 63 | "class": "Route", 64 | "gw": "${gateway}", 65 | "network": "default", 66 | "mtu": 1500 67 | }, 68 | "configsync": { 69 | "class": "ConfigSync", 70 | "configsyncIp": "/Common/external-self/address" 71 | }, 72 | "failoverAddress": { 73 | "class": "FailoverUnicast", 74 | "address": "/Common/external-self/address" 75 | }, 76 | "failoverGroup": { 77 | "class": "DeviceGroup", 78 | "type": "sync-failover", 79 | "members": ["${host1}.example.com", "${host2}.example.com"], 80 | "owner": "/Common/failoverGroup/members/0", 81 | "autoSync": true, 82 | "saveOnAutoSync": false, 83 | "networkFailover": true, 84 | "fullLoadOnSync": false, 85 | "asmSync": false 86 | }, 87 | "trust": { 88 | "class": "DeviceTrust", 89 | "localUsername": "${admin_user}", 90 | "localPassword": "${admin_password}", 91 | "remoteHost": "${remote_selfip}", 92 | "remoteUsername": "${admin_user}", 93 | "remotePassword": "${admin_password}" 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Azure_Secure_Enclave_Public_DMZ/link_LAW_to_Sentinel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garyluf5/f5_terraform/ab4ceb4c754d507d4db96b30cbb75ac53e30d61f/Azure_Secure_Enclave_Public_DMZ/link_LAW_to_Sentinel.png -------------------------------------------------------------------------------- /Azure_Secure_Enclave_Public_DMZ/onboard.tpl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # BIG-IPS ONBOARD SCRIPT 4 | 5 | LOG_FILE=${onboard_log} 6 | 7 | if [ ! -e $LOG_FILE ] 8 | then 9 | touch $LOG_FILE 10 | exec &>>$LOG_FILE 11 | else 12 | #if file exists, exit as only want to run once 13 | exit 14 | fi 15 | 16 | exec 1>$LOG_FILE 2>&1 17 | 18 | # CHECK TO SEE NETWORK IS READY 19 | CNT=0 20 | while true 21 | do 22 | STATUS=$(curl -s -k -I example.com | grep HTTP) 23 | if [[ $STATUS == *"200"* ]]; then 24 | echo "Got 200! VE is Ready!" 25 | break 26 | elif [ $CNT -le 6 ]; then 27 | echo "Status code: $STATUS Not done yet..." 28 | CNT=$[$CNT+1] 29 | else 30 | echo "GIVE UP..." 31 | break 32 | fi 33 | sleep 10 34 | done 35 | 36 | sleep 60 37 | 38 | ### DOWNLOAD ONBOARDING PKGS 39 | # Could be pre-packaged or hosted internally 40 | 41 | admin_username='${uname}' 42 | admin_password='${upassword}' 43 | CREDS="admin:"$admin_password 44 | TS_URL='${TS_URL}' 45 | TS_FN=$(basename "$TS_URL") 46 | DO_URL='${DO_onboard_URL}' 47 | DO_FN=$(basename "$DO_URL") 48 | AS3_URL='${AS3_URL}' 49 | AS3_FN=$(basename "$AS3_URL") 50 | 51 | mkdir -p ${libs_dir} 52 | 53 | echo -e "\n"$(date) "Download TS Pkg" 54 | curl -L -o ${libs_dir}/$TS_FN $TS_URL 55 | 56 | echo -e "\n"$(date) "Download Declarative Onboarding Pkg" 57 | curl -L -o ${libs_dir}/$DO_FN $DO_URL 58 | 59 | echo -e "\n"$(date) "Download AS3 Pkg" 60 | curl -L -o ${libs_dir}/$AS3_FN $AS3_URL 61 | 62 | # Copy the RPM Pkg to the file location 63 | cp ${libs_dir}/*.rpm /var/config/rest/downloads/ 64 | 65 | # Install Telemetry Streaming Pkg 66 | DATA="{\"operation\":\"INSTALL\",\"packageFilePath\":\"/var/config/rest/downloads/$TS_FN\"}" 67 | echo -e "\n"$(date) "Install TS Pkg" 68 | curl -u $CREDS -X POST http://localhost:8100/mgmt/shared/iapp/package-management-tasks -d $DATA 69 | 70 | sleep 10 71 | 72 | # Install Declarative Onboarding Pkg 73 | DATA="{\"operation\":\"INSTALL\",\"packageFilePath\":\"/var/config/rest/downloads/$DO_FN\"}" 74 | echo -e "\n"$(date) "Install DO Pkg" 75 | curl -u $CREDS -X POST http://localhost:8100/mgmt/shared/iapp/package-management-tasks -d $DATA 76 | 77 | sleep 10 78 | 79 | # Install AS3 Pkg 80 | DATA="{\"operation\":\"INSTALL\",\"packageFilePath\":\"/var/config/rest/downloads/$AS3_FN\"}" 81 | echo -e "\n"$(date) "Install AS3 Pkg" 82 | curl -u $CREDS -X POST http://localhost:8100/mgmt/shared/iapp/package-management-tasks -d $DATA 83 | 84 | sleep 10 85 | 86 | # Check DO Ready 87 | CNT=0 88 | while true 89 | do 90 | STATUS=$(curl -u $CREDS -X GET -s -k -I https://localhost/mgmt/shared/declarative-onboarding | grep HTTP) 91 | if [[ $STATUS == *"200"* ]]; then 92 | echo "Got 200! Declarative Onboarding is Ready!" 93 | break 94 | elif [ $CNT -le 6 ]; then 95 | echo "Status code: $STATUS DO Not done yet..." 96 | CNT=$[$CNT+1] 97 | else 98 | echo "GIVE UP..." 99 | break 100 | fi 101 | sleep 10 102 | done 103 | 104 | # Check AS3 Ready 105 | CNT=0 106 | while true 107 | do 108 | STATUS=$(curl -u $CREDS -X GET -s -k -I https://localhost/mgmt/shared/appsvcs/info | grep HTTP) 109 | if [[ $STATUS == *"200"* ]]; then 110 | echo "Got 200! AS3 is Ready!" 111 | break 112 | elif [ $CNT -le 6 ]; then 113 | echo "Status code: $STATUS AS3 Not done yet..." 114 | CNT=$[$CNT+1] 115 | else 116 | echo "GIVE UP..." 117 | break 118 | fi 119 | sleep 10 120 | done 121 | 122 | # Check TS Ready 123 | CNT=0 124 | while true 125 | do 126 | STATUS=$(curl -u $CREDS -X GET -s -k -I https://localhost/mgmt/shared/telemetry/declare | grep HTTP) 127 | if [[ $STATUS == *"200"* ]]; then 128 | echo "Got 200! TS is Ready!" 129 | break 130 | elif [ $CNT -le 6 ]; then 131 | echo "Status code: $STATUS TS Not done yet..." 132 | CNT=$[$CNT+1] 133 | else 134 | echo "GIVE UP..." 135 | break 136 | fi 137 | sleep 10 138 | done 139 | 140 | sleep 60 141 | -------------------------------------------------------------------------------- /Azure_Secure_Enclave_Public_DMZ/open_workbook_template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garyluf5/f5_terraform/ab4ceb4c754d507d4db96b30cbb75ac53e30d61f/Azure_Secure_Enclave_Public_DMZ/open_workbook_template.png -------------------------------------------------------------------------------- /Azure_Secure_Enclave_Public_DMZ/provider.tf: -------------------------------------------------------------------------------- 1 | # Configure the Microsoft Azure Provider, replace Service Principal and Subscription with your own 2 | provider "azurerm" { 3 | subscription_id = "${var.SP["subscription_id"]}" 4 | client_id = "${var.SP["client_id"]}" 5 | client_secret = "${var.SP["client_secret"]}" 6 | tenant_id = "${var.SP["tenant_id"]}" 7 | } 8 | 9 | -------------------------------------------------------------------------------- /Azure_Secure_Enclave_Public_DMZ/ts.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "Telemetry", 3 | "controls": { 4 | "class": "Controls", 5 | "logLevel": "info" 6 | }, 7 | "My_Poller": { 8 | "class": "Telemetry_System_Poller", 9 | "interval": 60 10 | }, 11 | "My_Listener": { 12 | "class": "Telemetry_Listener", 13 | "port": 6514 14 | }, 15 | "My_Consumer": { 16 | "class": "Telemetry_Consumer", 17 | "type": "Azure_Log_Analytics", 18 | "workspaceId": "${law_id}", 19 | "passphrase": { 20 | "cipherText": "${law_primkey}" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Azure_Secure_Enclave_Public_DMZ/variables.tf: -------------------------------------------------------------------------------- 1 | # REST API Setting 2 | variable rest_do_uri { default = "/mgmt/shared/declarative-onboarding" } 3 | variable rest_as3_uri { default = "/mgmt/shared/appsvcs/declare" } 4 | variable rest_ts_uri { default = "/mgmt/shared/telemetry/declare" } 5 | variable rest_do_method { default = "POST" } 6 | variable rest_as3_method { default = "POST" } 7 | variable rest_vm01_do_file {default = "vm01_do_data.json" } 8 | variable rest_vm02_do_file {default = "vm02_do_data.json" } 9 | variable rest_vm_as3_file {default = "vm_as3_data.json" } 10 | variable rest_vm_ts_file { default = "vm_ts_data.json" } 11 | 12 | # Azure Environment 13 | variable "SP" { 14 | type = "map" 15 | default = { 16 | subscription_id = "xxxxx" 17 | client_id = "xxxxx" 18 | client_secret = "xxxxx" 19 | tenant_id = "xxxxx" 20 | } 21 | } 22 | variable prefix { default = "zlusca" } 23 | variable uname { default = "azureuser" } 24 | variable upassword { default = "Default12345" } 25 | variable location { default = "eastus" } 26 | variable region { default = "East US" } 27 | 28 | # NETWORK 29 | variable cidr { default = "10.90.0.0/16" } 30 | variable "subnets" { 31 | type = "map" 32 | default = { 33 | "subnet1" = "10.90.1.0/24" 34 | "subnet2" = "10.90.2.0/24" 35 | "subnet3" = "10.90.3.0/24" 36 | } 37 | } 38 | variable app-cidr { default = "10.80.0.0/16" } 39 | variable "app-subnets" { 40 | type = "map" 41 | default = { 42 | "subnet1" = "10.80.1.0/24" 43 | } 44 | } 45 | variable f5vm01mgmt { default = "10.90.1.4" } 46 | variable f5vm01ext { default = "10.90.2.4" } 47 | variable f5vm01ext_sec { default = "10.90.2.11" } 48 | variable f5vm02mgmt { default = "10.90.1.5" } 49 | variable f5vm02ext { default = "10.90.2.5" } 50 | variable f5vm02ext_sec { default = "10.90.2.12" } 51 | variable backend01ext { default = "10.80.1.101" } 52 | 53 | # BIGIP Image 54 | variable instance_type { default = "Standard_DS4_v2" } 55 | variable image_name { default = "f5-big-all-2slot-byol" } 56 | variable product { default = "f5-big-ip-byol" } 57 | variable bigip_version { default = "latest" } 58 | 59 | # BIGIP Setup 60 | ## These licenses have been tested with F5-BIG-LTM-VE-1G-V16 base SKU 61 | variable license1 { default = "xxxxx" } 62 | variable license2 { default = "xxxxx" } 63 | variable host1_name { default = "f5vm01" } 64 | variable host2_name { default = "f5vm02" } 65 | variable dns_server { default = "8.8.8.8" } 66 | variable ntp_server { default = "0.us.pool.ntp.org" } 67 | variable timezone { default = "UTC" } 68 | ## Please check and update the latest DO URL from https://github.com/F5Networks/f5-declarative-onboarding/releases 69 | variable DO_onboard_URL { default = "https://github.com/garyluf5/f5tools/raw/master/f5-declarative-onboarding-1.7.0-3.noarch.rpm" } 70 | ## Please check and update the latest AS3 URL from https://github.com/F5Networks/f5-appsvcs-extension/releases/latest 71 | variable AS3_URL { default = "https://github.com/garyluf5/f5tools/raw/master/f5-appsvcs-3.14.0-4.noarch.rpm" } 72 | ## Please check and update the latest Telemetry Streaming from https://github.com/F5Networks/f5-telemetry-streaming/tree/master/dist 73 | variable TS_URL { default = "https://github.com/garyluf5/f5tools/raw/master/f5-telemetry-1.5.0-1.noarch.rpm" } 74 | variable libs_dir { default = "/config/cloud/azure/node_modules" } 75 | variable onboard_log { default = "/var/log/startup-script.log" } 76 | 77 | # TAGS 78 | variable purpose { default = "public" } 79 | variable environment { default = "f5env" } #ex. dev/staging/prod 80 | variable owner { default = "f5owner" } 81 | variable group { default = "f5group" } 82 | variable costcenter { default = "f5costcenter" } 83 | variable application { default = "f5app" } 84 | -------------------------------------------------------------------------------- /HA_via_api/AzureFailoverExtensionHighLevel1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garyluf5/f5_terraform/ab4ceb4c754d507d4db96b30cbb75ac53e30d61f/HA_via_api/AzureFailoverExtensionHighLevel1.gif -------------------------------------------------------------------------------- /HA_via_api/README.md: -------------------------------------------------------------------------------- 1 | # Deploying BIG-IP VEs in Azure - High Availability (Active/Standby): Two NICs 2 | 3 | ## Contents 4 | 5 | - [Introduction](#introduction) 6 | - [Prerequisites](#prerequisites) 7 | - [Important Configuration Notes](#important-configuration-notes) 8 | - [Security](#security) 9 | - [Configuration Example](#configuration-example) 10 | 11 | ## Introduction 12 | 13 | This solution uses an Terraform template to launch a two NIC deployment of a cloud-focused BIG-IP VE cluster (Active/Standby) in Microsoft Azure. Traffic flows to the HA BIG-IP VE which then send to DVWA app server. This is the standard cloud design where the BIG-IP VE instance is running with a dual interface, where both management and data plane traffic is processed on each one. 14 | 15 | The BIG-IP VEs have both the [Local Traffic Manager (LTM)](https://f5.com/products/big-ip/local-traffic-manager-ltm) and [Application Security Module (ASM)](https://www.f5.com/products/security/advanced-waf) modules enabled to provide advanced traffic management functionality. This means you can also configure the BIG-IP VE to enable F5's L4/L7 security features, access control, Advance WAF and intelligent traffic management. 16 | 17 | The one big thing in this Terraform accounted for is composing resources a bit differently to account for dependencies into Immutable/Mutable elements. i.e. stuff you would typically frequently change/mutate, such as traditional config on the BIG-IP. Once the template is deployed, there are certain resources (like the network infrastructure) that are fixed while others (like BIG-IP VMs and configurations) can be changed 18 | Ex. 19 | -> Run once 20 | - Deploy the entire infrastructure with all the neccessary resources, then we use Declarative Onboarding to configure the BIG-IP Cluster; AS3 to create a sample app proxy; then lastly use Service Discovery automatically add the DVWA container app to the LTM pool (Please note currently we also hardcode the node IP in the pool due to a bug in our AS3, which will be fixed in the next release) 21 | 22 | -> Run many X 23 | - [Redeploy BIG-IP for replacement or upgrade](#Redeploy-BIG-IP-for-replacement-or-upgrade) 24 | - [Reconfigure BIG-IP configurations](#Rerun-AS3-on-the-big-ip-ve) 25 | 26 | **Networking Stack Type:** This solution deploys into a new networking stack, which is created along with the solution. 27 | 28 | ## Version 29 | This template is tested and worked in the following version 30 | Terraform v0.12.6 31 | + provider.azurerm v1.32.1 32 | + provider.local v1.3.0 33 | + provider.null v2.1.2 34 | + provider.template v2.1.2 35 | 36 | ## Prerequisites 37 | 38 | - **Important**: When you configure the admin password for the BIG-IP VE in the template, you cannot use the character **#**. Additionally, there are a number of other special characters that you should avoid using for F5 product user accounts. See [K2873](https://support.f5.com/csp/article/K2873) for details. 39 | - This template requires a service principal. **Important**: you MUST have "OWNER" previlidge on the SP in order to assign role to the resources in your subscription. See the [Service Principal Setup section](#service-principal-authentication) for details, including required permissions. 40 | - The HA BIG-IP VMs use Azure RBAC role for the failover instead of using Service Prinicipal. 41 | - These BIG-IP VMs are deploy across different Availability Zones, please ensure the region you've chosen can support AZ 42 | - This deployment will be using the Terraform Azurerm provider to build out all the neccessary Azure objects. Therefore, Azure CLI is required. for installation, please follow this [Microsoft link](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-apt?view=azure-cli-latest) 43 | - If this is the first time to deploy the F5 image, the subscription used in this deployment needs to be enabled to programatically deploy. For more information, please refer to [Configure Programatic Deployment](https://azure.microsoft.com/en-us/blog/working-with-marketplace-images-on-azure-resource-manager/) 44 | 45 | ## Important configuration notes 46 | 47 | - All variables are configured in variables.tf 48 | - Azure Subscription and Service Principal are configured in provider.tf 49 | - This template would require Declarative Onboarding and AS3 packages for the initial configuration. As part of the onboarding script, it will download the RPMs respectively. So please see the [AS3 documentation](https://clouddocs.f5.com/products/extensions/f5-appsvcs-extension/3.5.1/) and [DO documentation](https://clouddocs.f5.com/products/extensions/f5-declarative-onboarding/latest/prereqs.html) for details on how to use AS3 and Declarative Onboarding on your BIG-IP VE(s). 50 | - onboard.tpl is the onboarding script, which is run by commandToExecute, and it will be copy to /var/lib/waagent/CustomData upon bootup. This script is basically responsible for downloading the neccessary DO and AS3 RPM files, installing them, and then executing the onboarding REST calls. 51 | - This template uses PayGo BIGIP image for the deployment (as default). If you would like to use BYOL, then these following steps are needed: 52 | 1. In the "variables.tf", specify the BYOL image and licenses regkeys. 53 | 2. In the "main.tf", uncomment the "local_sku" lines. 54 | 3. Add the following lines to the "cluster.json" file just under the "Common" declaration: 55 | ``` 56 | "myLicense": { 57 | "class": "License", 58 | "licenseType": "regKey", 59 | "regKey": "${local_sku}" 60 | }, 61 | ``` 62 | - In order to pass traffic from your clients to the servers, after launching the template, you must create virtual server(s) on the BIG-IP VE. See [Creating a virtual server](#creating-virtual-servers-on-the-big-ip-ve). 63 | - See the **[Configuration Example](#configuration-example)** section for a configuration diagram and description for this solution. 64 | 65 | ### Template parameters 66 | 67 | | Parameter | Required | Description | 68 | | --- | --- | --- | 69 | | prefix | Yes | This value is insert in the beginning of each Azure object, try keeps it alpha-numeric without any special character | 70 | | rest_do_uri | Yes | URI of the Declarative Onboarding REST call. | 71 | | rest_as3_uri | Yes | URI of the AS3 REST call. | 72 | | rest_CF_uri | Yes | URI of the Cloud-Failover REST call. | 73 | | rest_do_method | Yes | Available options are GET, POST, and DELETE. | 74 | | rest_AS3_method | Yes | Available options are GET, POST, and DELETE. | 75 | | rest_vm01_do_file | Yes | Terraform will generate the vm01 DO json file, where you can manually run it again for debugging. | 76 | | rest_vm02_do_file | Yes | Terraform will generate the vm02 DO json file, where you can manually run it again for debugging. | 77 | | rest_vm_as3_file | Yes | Terraform will generate the AS3 json file, where you can manually run it again for debugging. | 78 | | rest_vm_CF_file | Yes | Terraform will generate the CF json file, where you can manually run it again for debugging. | 79 | | SP | YES | This is the service principal of your Azure subscription. | 80 | | uname | Yes | User name for the Virtual Machine. | 81 | | upassword | Yes | Password for the Virtual Machine. | 82 | | location | Yes | Location of the deployment. | 83 | | region | Yes | Region of the deployment. | 84 | | cidr | Yes | IP Address range of the Virtual Network. | 85 | | subnet1 | Yes | Subnet IP range of the management network. | 86 | | subnet2 | Yes | Subnet IP range of the external network. | 87 | | subnet3 | No | Subnet IP range of the internal network. | 88 | | managed_route1 | Yes | A UDR route can used for testing managed-route failover. | 89 | | f5vm01mgmt | Yes | IP address for 1st BIG-IP's management interface. | 90 | | f5vm02mgmt | Yes | IP address for 2nd BIG-IP's management interface. | 91 | | f5vm01ext | Yes | IP address for 1st BIG-IP's external interface. | 92 | | f5vm01ext_sec | Yes | Secondary IP address for 1st BIG-IP's external interface. | 93 | | f5vm02ext | Yes | IP address for 2nd BIG-IP's external interface. | 94 | | f5vm02ext_sec | Yes | Secondary IP address for 2nd BIG-IP's external interface. | 95 | | instance_type | Yes | Azure instance to be used for the BIG-IP VE. | 96 | | product | Yes | Azure BIG-IP VE Offer. | 97 | | bigip_version | Yes | It is set to default to use the latest software. | 98 | | image_name | Yes | F5 SKU (image) to you want to deploy. Note: The disk size of the VM will be determined based on the option you select. **Important**: If intending to provision multiple modules, ensure the appropriate value is selected, such as ****AllTwoBootLocations or AllOneBootLocation****. | 99 | | license1 | No | The license token for the F5 BIG-IP VE (BYOL). | 100 | | license2 | No | The license token for the F5 BIG-IP VE (BYOL). | 101 | | host1_name | Yes | Hostname for the 1st BIG-IP. | 102 | | host2_name | Yes | Hostname for the 2nd BIG-IP. | 103 | | ntp_server | Yes | Leave the default NTP server the BIG-IP uses, or replace the default NTP server with the one you want to use. | 104 | | timezone | Yes | If you would like to change the time zone the BIG-IP uses, enter the time zone you want to use. This is based on the tz database found in /usr/share/zoneinfo (see the full list [here](https://github.com/F5Networks/f5-azure-arm-templates/blob/master/azure-timezone-list.md)). Example values: UTC, US/Pacific, US/Eastern, Europe/London or Asia/Singapore. | 105 | | dns_server | Yes | Least the default DNS server the BIG-IP uses, or replace the default DNS server with the one you want to use. | 106 | | DO_onboard_URL | Yes | This is the raw github URL for downloading the Declarative Onboarding RPM | 107 | | AS3_URL | Yes | This is the raw github URL for downloading the AS3 RPM. | 108 | | TS_URL | Yes | This is the raw github URL for downloading the Telemetry RPM. | 109 | | CF_URL | Yes | This is the raw github URL for downloading the Cloud-Failover RPM. | 110 | | libs_dir | Yes | This is where all the temporary libs and RPM will be store in BIG-IP. | 111 | | onboard_log | Yes | This is where the onboarding script logs all the events. | 112 | | f5_cloud_failover_label | Yes | This is a tag used for failover. | 113 | | f5_cloud_failover_nic_map | Yes | This is a tag used for failover NIC. | 114 | 115 | ## Configuration Example 116 | 117 | The following is an example configuration diagram for this solution deployment. In this scenario, all access to the BIG-IP VE cluster (Active/Standby) is through an ALB. The IP addresses in this example may be different in your implementation. 118 | 119 | ![Configuration Example](./AzureFailoverExtensionHighLevel1.gif) 120 | 121 | 122 | ## Documentation 123 | 124 | For more information on F5 solutions for Azure, including manual configuration procedures for some deployment scenarios, see the Azure section of [Cloud Failover Doc](https://clouddocs.f5networks.net/products/extensions/f5-cloud-failover/latest/userguide/azure.html). 125 | 126 | ## Creating virtual servers on the BIG-IP VE 127 | 128 | In order to pass traffic from your clients to the servers through the BIG-IP system, you must create a virtual server on the BIG-IP VE. In this template, it creates 2 VIPs, one for public internet facing and one for private internal usage. They are preconfigured as an example and configured the same way as on-prem BIG-IP. 129 | 130 | ## Redeploy BIG-IP for replacement or upgrade 131 | This example illustrates how to replace the BIG-IP VE 132 | 1. Revoke the problematic BIG-IP VE's license (if BYOL) 133 | 2. Run command 134 | ``` 135 | terraform destroy -target azurerm_virtual_machine.f5vm02 136 | ``` 137 | 3. Run command 138 | ``` 139 | terraform apply 140 | ``` 141 | 4. At this time, you have 2 standalone BIG-IP VEs behind the Azure LB, which is fine. Repeate step 1 to step 3 on the other BIG-IP VE otherwise, the Device Trust won't be configured correctly 142 | 143 | 144 | This example illustrate how to upgrade the BIG-IP VEs (remember, when replace a VE, we replace both, can't be just single VE) 145 | 1. Change the 'bigip_version' variable to the desired release 146 | 2. Revoke the problematic BIG-IP VE's license 147 | 3. Run command 148 | ``` 149 | terraform destroy -target azurerm_virtual_machine.f5vm02 150 | ``` 151 | 4. Run command 152 | ``` 153 | terraform apply 154 | ``` 155 | 5. At this time, you have 2 standalone BIG-IP VEs behind the Azure LB, which is fine. Repeate step 2 to step 4 on the other BIG-IP VE otherwise, the Device Trust won't be configured correctly 156 | 157 | ## Rerun AS3 on the Big-ip ve 158 | - This example illustrate how to run your own custom AS3, you can have a catalog of AS3 and repeat this steps as many times as desired 159 | ``` 160 | terraform taint null_resource.f5vm_AS3 161 | terraform apply -target null_resource.f5vm_AS3 -var "rest_as3_method=POST" -var "rest_vm_as3_file=test.json" 162 | ``` 163 | - If you would like to re-run your DO json, it would be similar to the above procedure. 164 | -------------------------------------------------------------------------------- /HA_via_api/as3.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "AS3", 3 | "action": "deploy", 4 | "persist": true, 5 | "declaration": { 6 | "class": "ADC", 7 | "schemaVersion": "3.13.0", 8 | "id": "123abc", 9 | "label": "Sample 1", 10 | "remark": "HTTPS with predictive-node pool", 11 | "Sample_01": { 12 | "class": "Tenant", 13 | "A1": { 14 | "class": "Application", 15 | "template": "https", 16 | "serviceMain": { 17 | "class": "Service_HTTPS", 18 | "virtualPort": 443, 19 | "virtualAddresses": [ 20 | "${publicvip}", 21 | "${privatevip}" 22 | ], 23 | "pool": "web_pool", 24 | "serverTLS": "webtls" 25 | }, 26 | "web_pool": { 27 | "class": "Pool", 28 | "monitors": [ 29 | "tcp" 30 | ], 31 | "members": [ 32 | { 33 | "servicePort": 80, 34 | "addressDiscovery": "azure", 35 | "updateInterval": 10, 36 | "tagKey": "application", 37 | "tagValue": "app1", 38 | "addressRealm": "private", 39 | "resourceGroup": "${rg_name}", 40 | "subscriptionId": "${subscription_id}", 41 | "directoryId": "${tenant_id}", 42 | "applicationId": "${client_id}", 43 | "apiAccessKey": "${client_secret}", 44 | "credentialUpdate": false 45 | } 46 | ] 47 | }, 48 | "webtls": { 49 | "class": "TLS_Server", 50 | "certificates": [{ 51 | "certificate": "webcert" 52 | }] 53 | }, 54 | "webcert": { 55 | "class": "Certificate", 56 | "remark": "in practice we recommend using a passphrase", 57 | "certificate": "-----BEGIN CERTIFICATE-----\nMIICnDCCAgWgAwIBAgIJAJ5n2b0OCEjwMA0GCSqGSIb3DQEBCwUAMGcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMRQwEgYDVQQKDAtmNV9OZXR3b3JrczEbMBkGA1UEAwwSc2FtcGxlLmV4YW1wbGUubmV0MB4XDTE3MTEyNjE5NTAyNFoXDTE4MDIyNTE5NTAyNFowZzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxFDASBgNVBAoMC2Y1X05ldHdvcmtzMRswGQYDVQQDDBJzYW1wbGUuZXhhbXBsZS5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALEsuXmSXVQpYjrZPW+WiTBjn491mwZYT7Q92V1HlSBtM6WdWlK1aZN5sovfKtOX7Yrm8xa+e4o/zJ2QYLyyv5O+t2EGN/4qUEjEAPY9mwJdfzRQy6Hyzm84J0QkTuUJ/EjNuPji3D0QJRALUTzu1UqqDCEtiN9OGyXEkh7uvb7BAgMBAAGjUDBOMB0GA1UdDgQWBBSVHPNrGWrjWyZvckQxFYWO59FRFjAfBgNVHSMEGDAWgBSVHPNrGWrjWyZvckQxFYWO59FRFjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBAJeJ9SEckEwPhkXOm+IuqfbUS/RcziifBCTmVyE+Fa/j9pKSYTgiEBNdbJeBEa+gPMlQtbV7Y2dy8TKx/8axVBHiXC5geDML7caxOrAyHYBpnx690xJTh5OIORBBM/a/NvaR+P3CoVebr/NPRh9oRNxnntnqvqD7SW0U3ZPe3tJc\n-----END CERTIFICATE-----", 58 | "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-256-CBC,D8FFCE6B255601587CB54EC29B737D31\n\nkv4Fc3Jn0Ujkj0yRjt+gQQfBLSNF2aRLUENXnlr7Xpzqu0Ahr3jS1bAAnd8IWnsR\nyILqVmKsYF2DoHh0tWiEAQ7/y/fe5DTFhK7N4Wml6kp2yVMkP6KC4ssyYPw27kjK\nDBwBZ5O8Ioej08A5sgsLCmglbmtSPHJUn14pQnMTmLOpEtOsu6S+2ibPgSNpdg0b\nCAJNG/KHe+Vkx59qNDyDeKb7FZOlsX30+y67zUq9GQqJEDuysPJ2BUNP0IJXAjst\nFIt1qNoZew+5KDYs7u/lPxcMGTirUhgI84Jy4WcDvSOsP/tKlxj04TbIE3epmSKy\n+TihHkwY7ngIGtcm3Sfqk5jz2RXoj1/Ac3SW8kVTYaOUogBhn7zAq4Wju6Et4hQG\nRGapsJp1aCeZ/a4RCDTxspcKoMaRa97/URQb0hBRGx3DGUhzpmX9zl7JI2Xa5D3R\nmdBXtjLKYJTdIMdd27prBEKhMUpae2rz5Mw4J907wZeBq/wu+zp8LAnecfTe2nGY\nE32x1U7gSEdYOGqnwxsOexb1jKgCa67Nw9TmcMPV8zmH7R9qdvgxAbAtwBl1F9OS\nfcGaC7epf1AjJLtaX7krWmzgASHl28Ynh9lmGMdv+5QYMZvKG0LOg/n3m8uJ6sKy\nIzzvaJswwn0j5P5+czyoV5CvvdCfKnNb+3jUEN8I0PPwjBGKr4B1ojwhogTM248V\nHR69D6TxFVMfGpyJhCPkbGEGbpEpcffpgKuC/mEtMqyDQXJNaV5HO6HgAJ9F1P6v\n5ehHHTMRvzCCFiwndHdlMXUjqSNjww6me6dr6LiAPbejdzhL2vWx1YqebOcwQx3G\n-----END RSA PRIVATE KEY-----", 59 | "passphrase": { 60 | "ciphertext": "ZjVmNQ==", 61 | "protected": "eyJhbGciOiJkaXIiLCJlbmMiOiJub25lIn0" 62 | } 63 | } 64 | } 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /HA_via_api/cluster.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0.0", 3 | "class": "Device", 4 | "label": "Basic onboarding", 5 | "Common": { 6 | "class": "Tenant", 7 | "hostname": "${local_host}.example.com", 8 | "dbvars": { 9 | "class": "DbVariables", 10 | "ui.advisory.enabled": true, 11 | "ui.advisory.color": "green", 12 | "ui.advisory.text": "/Common/hostname" 13 | }, 14 | "myDns": { 15 | "class": "DNS", 16 | "nameServers": [ 17 | "${dns_server}", 18 | "2001:4860:4860::8844" 19 | ], 20 | "search": [ 21 | "f5.com" 22 | ] 23 | }, 24 | "myNtp": { 25 | "class": "NTP", 26 | "servers": [ 27 | "${ntp_server}", 28 | "0.pool.ntp.org", 29 | "1.pool.ntp.org" 30 | ], 31 | "timezone": "${timezone}" 32 | }, 33 | "myProvisioning": { 34 | "class": "Provision", 35 | "ltm": "nominal", 36 | "asm": "nominal" 37 | }, 38 | "external": { 39 | "class": "VLAN", 40 | "tag": 4094, 41 | "mtu": 1500, 42 | "interfaces": [ 43 | { 44 | "name": "1.1", 45 | "tagged": false 46 | } 47 | ] 48 | }, 49 | "external-self": { 50 | "class": "SelfIp", 51 | "address": "${local_selfip}/24", 52 | "vlan": "external", 53 | "allowService": "default", 54 | "trafficGroup": "traffic-group-local-only" 55 | }, 56 | "default": { 57 | "class": "Route", 58 | "gw": "${gateway}", 59 | "network": "default", 60 | "mtu": 1500 61 | }, 62 | "configsync": { 63 | "class": "ConfigSync", 64 | "configsyncIp": "/Common/external-self/address" 65 | }, 66 | "failoverAddress": { 67 | "class": "FailoverUnicast", 68 | "address": "/Common/external-self/address" 69 | }, 70 | "failoverGroup": { 71 | "class": "DeviceGroup", 72 | "type": "sync-failover", 73 | "members": ["${host1}.example.com", "${host2}.example.com"], 74 | "owner": "/Common/failoverGroup/members/0", 75 | "autoSync": true, 76 | "saveOnAutoSync": false, 77 | "networkFailover": true, 78 | "fullLoadOnSync": false, 79 | "asmSync": false 80 | }, 81 | "trust": { 82 | "class": "DeviceTrust", 83 | "localUsername": "${admin_user}", 84 | "localPassword": "${admin_password}", 85 | "remoteHost": "${remote_selfip}", 86 | "remoteUsername": "${admin_user}", 87 | "remotePassword": "${admin_password}" 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /HA_via_api/failover.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "Cloud_Failover", 3 | "environment": "azure", 4 | "externalStorage": { 5 | "scopingTags": { 6 | "f5_cloud_failover_label": "${f5_cloud_failover_label}" 7 | } 8 | }, 9 | "failoverAddresses": { 10 | "scopingTags": { 11 | "f5_cloud_failover_label": "${f5_cloud_failover_label}" 12 | } 13 | }, 14 | "failoverRoutes": { 15 | "scopingTags": { 16 | "f5_cloud_failover_label": "${f5_cloud_failover_label}" 17 | }, 18 | "scopingAddressRanges": [ 19 | "${managed_route1}" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /HA_via_api/main.tf: -------------------------------------------------------------------------------- 1 | # Create a Resource Group for the new Virtual Machine 2 | resource "azurerm_resource_group" "main" { 3 | name = "${var.prefix}_rg" 4 | location = "${var.location}" 5 | } 6 | 7 | # Create a Virtual Network within the Resource Group 8 | resource "azurerm_virtual_network" "main" { 9 | name = "${var.prefix}-network" 10 | address_space = ["${var.cidr}"] 11 | resource_group_name = "${azurerm_resource_group.main.name}" 12 | location = "${azurerm_resource_group.main.location}" 13 | } 14 | 15 | # Create the Storage Account 16 | resource "azurerm_storage_account" "mystorage" { 17 | name = "${var.prefix}mystorage" 18 | resource_group_name = "${azurerm_resource_group.main.name}" 19 | location = "${azurerm_resource_group.main.location}" 20 | account_tier = "Standard" 21 | account_replication_type = "LRS" 22 | 23 | tags = { 24 | environment = "${var.environment}" 25 | owner = "${var.owner}" 26 | group = "${var.group}" 27 | costcenter = "${var.costcenter}" 28 | application = "${var.application}" 29 | f5_cloud_failover_label = "${var.f5_cloud_failover_label}" 30 | } 31 | } 32 | 33 | # Create Route Table 34 | resource "azurerm_route_table" "udr" { 35 | name = "udr" 36 | location = "${azurerm_resource_group.main.location}" 37 | resource_group_name = "${azurerm_resource_group.main.name}" 38 | disable_bgp_route_propagation = false 39 | 40 | route { 41 | name = "route1" 42 | address_prefix = "${var.managed_route1}" 43 | next_hop_type = "VirtualAppliance" 44 | next_hop_in_ip_address = "${azurerm_network_interface.vm01-ext-nic.private_ip_address}" 45 | } 46 | 47 | tags = { 48 | f5_cloud_failover_label = "${var.f5_cloud_failover_label}" 49 | f5_self_ips = "${azurerm_network_interface.vm01-ext-nic.private_ip_address},${azurerm_network_interface.vm02-ext-nic.private_ip_address}" 50 | } 51 | } 52 | 53 | # Create the first Subnet within the Virtual Network 54 | resource "azurerm_subnet" "Mgmt" { 55 | name = "Mgmt" 56 | virtual_network_name = "${azurerm_virtual_network.main.name}" 57 | resource_group_name = "${azurerm_resource_group.main.name}" 58 | address_prefix = "${var.subnets["subnet1"]}" 59 | } 60 | 61 | # Create the second Subnet within the Virtual Network 62 | resource "azurerm_subnet" "External" { 63 | name = "External" 64 | virtual_network_name = "${azurerm_virtual_network.main.name}" 65 | resource_group_name = "${azurerm_resource_group.main.name}" 66 | address_prefix = "${var.subnets["subnet2"]}" 67 | } 68 | 69 | # Obtain Gateway IP for each Subnet 70 | locals { 71 | depends_on = ["azurerm_subnet.Mgmt", "azurerm_subnet.External"] 72 | mgmt_gw = "${cidrhost(azurerm_subnet.Mgmt.address_prefix, 1)}" 73 | ext_gw = "${cidrhost(azurerm_subnet.External.address_prefix, 1)}" 74 | } 75 | 76 | # Create a Public IP for the Virtual Machines 77 | resource "azurerm_public_ip" "vm01mgmtpip" { 78 | name = "${var.prefix}-vm01-mgmt-pip" 79 | location = "${azurerm_resource_group.main.location}" 80 | sku = "Standard" 81 | zones = [1] 82 | resource_group_name = "${azurerm_resource_group.main.name}" 83 | allocation_method = "Static" 84 | 85 | tags = { 86 | Name = "${var.environment}-vm01-mgmt-public-ip" 87 | environment = "${var.environment}" 88 | owner = "${var.owner}" 89 | group = "${var.group}" 90 | costcenter = "${var.costcenter}" 91 | application = "${var.application}" 92 | } 93 | } 94 | 95 | resource "azurerm_public_ip" "vm01selfpip" { 96 | name = "${var.prefix}-vm01-self-pip" 97 | location = "${azurerm_resource_group.main.location}" 98 | sku = "Standard" 99 | zones = [1] 100 | resource_group_name = "${azurerm_resource_group.main.name}" 101 | allocation_method = "Static" 102 | 103 | tags = { 104 | Name = "${var.environment}-vm01-self-public-ip" 105 | environment = "${var.environment}" 106 | owner = "${var.owner}" 107 | group = "${var.group}" 108 | costcenter = "${var.costcenter}" 109 | application = "${var.application}" 110 | } 111 | } 112 | 113 | resource "azurerm_public_ip" "vm02mgmtpip" { 114 | name = "${var.prefix}-vm02-mgmt-pip" 115 | location = "${azurerm_resource_group.main.location}" 116 | sku = "Standard" 117 | zones = [2] 118 | resource_group_name = "${azurerm_resource_group.main.name}" 119 | allocation_method = "Static" 120 | 121 | tags = { 122 | Name = "${var.environment}-vm02-mgmt-public-ip" 123 | environment = "${var.environment}" 124 | owner = "${var.owner}" 125 | group = "${var.group}" 126 | costcenter = "${var.costcenter}" 127 | application = "${var.application}" 128 | } 129 | } 130 | 131 | resource "azurerm_public_ip" "vm02selfpip" { 132 | name = "${var.prefix}-vm02-self-pip" 133 | location = "${azurerm_resource_group.main.location}" 134 | sku = "Standard" 135 | zones = [2] 136 | resource_group_name = "${azurerm_resource_group.main.name}" 137 | allocation_method = "Static" 138 | 139 | tags = { 140 | Name = "${var.environment}-vm02-self-public-ip" 141 | environment = "${var.environment}" 142 | owner = "${var.owner}" 143 | group = "${var.group}" 144 | costcenter = "${var.costcenter}" 145 | application = "${var.application}" 146 | } 147 | } 148 | 149 | 150 | resource "azurerm_public_ip" "pubvippip" { 151 | name = "${var.prefix}-pubvip-pip" 152 | location = "${azurerm_resource_group.main.location}" 153 | sku = "Standard" 154 | zones = [1] 155 | resource_group_name = "${azurerm_resource_group.main.name}" 156 | allocation_method = "Static" 157 | 158 | tags = { 159 | Name = "${var.environment}-pubvip-public-ip" 160 | environment = "${var.environment}" 161 | owner = "${var.owner}" 162 | group = "${var.group}" 163 | costcenter = "${var.costcenter}" 164 | application = "${var.application}" 165 | } 166 | } 167 | 168 | # Create a Network Security Group with some rules 169 | resource "azurerm_network_security_group" "main" { 170 | name = "${var.prefix}-nsg" 171 | location = "${azurerm_resource_group.main.location}" 172 | resource_group_name = "${azurerm_resource_group.main.name}" 173 | 174 | security_rule { 175 | name = "allow_SSH" 176 | description = "Allow SSH access" 177 | priority = 100 178 | direction = "Inbound" 179 | access = "Allow" 180 | protocol = "Tcp" 181 | source_port_range = "*" 182 | destination_port_range = "22" 183 | source_address_prefix = "*" 184 | destination_address_prefix = "*" 185 | } 186 | 187 | security_rule { 188 | name = "allow_HTTP" 189 | description = "Allow HTTP access" 190 | priority = 110 191 | direction = "Inbound" 192 | access = "Allow" 193 | protocol = "Tcp" 194 | source_port_range = "*" 195 | destination_port_range = "80" 196 | source_address_prefix = "*" 197 | destination_address_prefix = "*" 198 | } 199 | 200 | security_rule { 201 | name = "allow_HTTPS" 202 | description = "Allow HTTPS access" 203 | priority = 120 204 | direction = "Inbound" 205 | access = "Allow" 206 | protocol = "Tcp" 207 | source_port_range = "*" 208 | destination_port_range = "443" 209 | source_address_prefix = "*" 210 | destination_address_prefix = "*" 211 | } 212 | 213 | security_rule { 214 | name = "allow_RDP" 215 | description = "Allow RDP access" 216 | priority = 130 217 | direction = "Inbound" 218 | access = "Allow" 219 | protocol = "Tcp" 220 | source_port_range = "*" 221 | destination_port_range = "3389" 222 | source_address_prefix = "*" 223 | destination_address_prefix = "*" 224 | } 225 | 226 | security_rule { 227 | name = "allow_APP_HTTPS" 228 | description = "Allow HTTPS access" 229 | priority = 140 230 | direction = "Inbound" 231 | access = "Allow" 232 | protocol = "Tcp" 233 | source_port_range = "*" 234 | destination_port_range = "8443" 235 | source_address_prefix = "*" 236 | destination_address_prefix = "*" 237 | } 238 | 239 | tags = { 240 | Name = "${var.environment}-bigip-sg" 241 | environment = "${var.environment}" 242 | owner = "${var.owner}" 243 | group = "${var.group}" 244 | costcenter = "${var.costcenter}" 245 | application = "${var.application}" 246 | } 247 | } 248 | 249 | # Create the first network interface card for Management 250 | resource "azurerm_network_interface" "vm01-mgmt-nic" { 251 | name = "${var.prefix}-mgmt0" 252 | location = "${azurerm_resource_group.main.location}" 253 | resource_group_name = "${azurerm_resource_group.main.name}" 254 | network_security_group_id = "${azurerm_network_security_group.main.id}" 255 | 256 | ip_configuration { 257 | name = "primary" 258 | subnet_id = "${azurerm_subnet.Mgmt.id}" 259 | private_ip_address_allocation = "Static" 260 | private_ip_address = "${var.f5vm01mgmt}" 261 | public_ip_address_id = "${azurerm_public_ip.vm01mgmtpip.id}" 262 | } 263 | 264 | tags = { 265 | Name = "${var.environment}-vm01-mgmt-int" 266 | environment = "${var.environment}" 267 | owner = "${var.owner}" 268 | group = "${var.group}" 269 | costcenter = "${var.costcenter}" 270 | application = "${var.application}" 271 | } 272 | } 273 | 274 | resource "azurerm_network_interface" "vm02-mgmt-nic" { 275 | name = "${var.prefix}-mgmt1" 276 | location = "${azurerm_resource_group.main.location}" 277 | resource_group_name = "${azurerm_resource_group.main.name}" 278 | network_security_group_id = "${azurerm_network_security_group.main.id}" 279 | 280 | ip_configuration { 281 | name = "primary" 282 | subnet_id = "${azurerm_subnet.Mgmt.id}" 283 | private_ip_address_allocation = "Static" 284 | private_ip_address = "${var.f5vm02mgmt}" 285 | public_ip_address_id = "${azurerm_public_ip.vm02mgmtpip.id}" 286 | } 287 | 288 | tags = { 289 | Name = "${var.environment}-vm02-mgmt-int" 290 | environment = "${var.environment}" 291 | owner = "${var.owner}" 292 | group = "${var.group}" 293 | costcenter = "${var.costcenter}" 294 | application = "${var.application}" 295 | } 296 | } 297 | 298 | # Create the second network interface card for External 299 | resource "azurerm_network_interface" "vm01-ext-nic" { 300 | name = "${var.prefix}-ext0" 301 | location = "${azurerm_resource_group.main.location}" 302 | resource_group_name = "${azurerm_resource_group.main.name}" 303 | network_security_group_id = "${azurerm_network_security_group.main.id}" 304 | 305 | ip_configuration { 306 | name = "f5vm-self-ipconfig" 307 | subnet_id = "${azurerm_subnet.External.id}" 308 | private_ip_address_allocation = "Static" 309 | private_ip_address = "${var.f5vm01ext}" 310 | primary = true 311 | public_ip_address_id = "${azurerm_public_ip.vm01selfpip.id}" 312 | } 313 | 314 | ip_configuration { 315 | name = "${var.prefix}-ext-ipconfig0" 316 | subnet_id = "${azurerm_subnet.External.id}" 317 | private_ip_address_allocation = "Static" 318 | private_ip_address = "${var.f5privatevip}" 319 | } 320 | 321 | ip_configuration { 322 | name = "${var.prefix}-ext-ipconfig1" 323 | subnet_id = "${azurerm_subnet.External.id}" 324 | private_ip_address_allocation = "Static" 325 | private_ip_address = "${var.f5publicvip}" 326 | public_ip_address_id = "${azurerm_public_ip.pubvippip.id}" 327 | } 328 | 329 | tags = { 330 | Name = "${var.environment}-vm01-ext-int" 331 | environment = "${var.environment}" 332 | owner = "${var.owner}" 333 | group = "${var.group}" 334 | costcenter = "${var.costcenter}" 335 | application = "${var.application}" 336 | f5_cloud_failover_label = "${var.f5_cloud_failover_label}" 337 | f5_cloud_failover_nic_map = "${var.f5_cloud_failover_nic_map}" 338 | } 339 | } 340 | 341 | resource "azurerm_network_interface" "vm02-ext-nic" { 342 | name = "${var.prefix}-ext1" 343 | location = "${azurerm_resource_group.main.location}" 344 | resource_group_name = "${azurerm_resource_group.main.name}" 345 | network_security_group_id = "${azurerm_network_security_group.main.id}" 346 | 347 | ip_configuration { 348 | name = "f5vm-self-ipconfig" 349 | subnet_id = "${azurerm_subnet.External.id}" 350 | private_ip_address_allocation = "Static" 351 | private_ip_address = "${var.f5vm02ext}" 352 | primary = true 353 | public_ip_address_id = "${azurerm_public_ip.vm02selfpip.id}" 354 | } 355 | 356 | tags = { 357 | Name = "${var.environment}-vm02-ext-int" 358 | environment = "${var.environment}" 359 | owner = "${var.owner}" 360 | group = "${var.group}" 361 | costcenter = "${var.costcenter}" 362 | application = "${var.application}" 363 | f5_cloud_failover_label = "${var.f5_cloud_failover_label}" 364 | f5_cloud_failover_nic_map = "${var.f5_cloud_failover_nic_map}" 365 | } 366 | } 367 | 368 | resource "azurerm_network_interface" "backend01-ext-nic" { 369 | name = "${var.prefix}-backend01-ext-nic" 370 | location = "${azurerm_resource_group.main.location}" 371 | resource_group_name = "${azurerm_resource_group.main.name}" 372 | network_security_group_id = "${azurerm_network_security_group.main.id}" 373 | 374 | ip_configuration { 375 | name = "primary" 376 | subnet_id = "${azurerm_subnet.External.id}" 377 | private_ip_address_allocation = "Static" 378 | private_ip_address = "${var.backend01ext}" 379 | primary = true 380 | } 381 | 382 | tags = { 383 | Name = "${var.environment}-backend01-ext-int" 384 | environment = "${var.environment}" 385 | owner = "${var.owner}" 386 | group = "${var.group}" 387 | costcenter = "${var.costcenter}" 388 | application = "app1" 389 | } 390 | } 391 | 392 | 393 | # Setup Onboarding scripts 394 | data "template_file" "vm_onboard" { 395 | template = "${file("${path.module}/onboard.tpl")}" 396 | 397 | vars = { 398 | uname = "${var.uname}" 399 | upassword = "${var.upassword}" 400 | DO_onboard_URL = "${var.DO_onboard_URL}" 401 | AS3_URL = "${var.AS3_URL}" 402 | TS_URL = "${var.TS_URL}" 403 | CF_URL = "${var.CF_URL}" 404 | libs_dir = "${var.libs_dir}" 405 | onboard_log = "${var.onboard_log}" 406 | mgmt_gw = "${local.mgmt_gw}" 407 | } 408 | } 409 | 410 | data "template_file" "vm01_do_json" { 411 | template = "${file("${path.module}/cluster.json")}" 412 | 413 | vars = { 414 | #Uncomment the following line for BYOL 415 | #local_sku = "${var.license1}" 416 | 417 | host1 = "${var.host1_name}" 418 | host2 = "${var.host2_name}" 419 | local_host = "${var.host1_name}" 420 | local_selfip = "${var.f5vm01ext}" 421 | remote_host = "${var.host2_name}" 422 | remote_selfip = "${var.f5vm02ext}" 423 | gateway = "${local.ext_gw}" 424 | dns_server = "${var.dns_server}" 425 | ntp_server = "${var.ntp_server}" 426 | timezone = "${var.timezone}" 427 | admin_user = "${var.uname}" 428 | admin_password = "${var.upassword}" 429 | } 430 | } 431 | 432 | data "template_file" "vm02_do_json" { 433 | template = "${file("${path.module}/cluster.json")}" 434 | 435 | vars = { 436 | #Uncomment the following line for BYOL 437 | #local_sku = "${var.license2}" 438 | 439 | host1 = "${var.host1_name}" 440 | host2 = "${var.host2_name}" 441 | local_host = "${var.host2_name}" 442 | local_selfip = "${var.f5vm02ext}" 443 | remote_host = "${var.host1_name}" 444 | remote_selfip = "${var.f5vm01ext}" 445 | gateway = "${local.ext_gw}" 446 | dns_server = "${var.dns_server}" 447 | ntp_server = "${var.ntp_server}" 448 | timezone = "${var.timezone}" 449 | admin_user = "${var.uname}" 450 | admin_password = "${var.upassword}" 451 | } 452 | } 453 | 454 | data "template_file" "as3_json" { 455 | template = "${file("${path.module}/as3.json")}" 456 | 457 | vars = { 458 | rg_name = "${azurerm_resource_group.main.name}" 459 | subscription_id = "${var.SP["subscription_id"]}" 460 | tenant_id = "${var.SP["tenant_id"]}" 461 | client_id = "${var.SP["client_id"]}" 462 | client_secret = "${var.SP["client_secret"]}" 463 | publicvip = "${var.f5publicvip}" 464 | privatevip = "${var.f5privatevip}" 465 | } 466 | } 467 | 468 | data "template_file" "failover_json" { 469 | template = "${file("${path.module}/failover.json")}" 470 | 471 | vars = { 472 | f5_cloud_failover_label = "${var.f5_cloud_failover_label}" 473 | managed_route1 = "${var.managed_route1}" 474 | } 475 | } 476 | 477 | 478 | # Create F5 BIGIP VMs 479 | resource "azurerm_virtual_machine" "f5vm01" { 480 | name = "${var.prefix}-f5vm01" 481 | location = "${azurerm_resource_group.main.location}" 482 | zones = [1] 483 | resource_group_name = "${azurerm_resource_group.main.name}" 484 | primary_network_interface_id = "${azurerm_network_interface.vm01-mgmt-nic.id}" 485 | network_interface_ids = ["${azurerm_network_interface.vm01-mgmt-nic.id}", "${azurerm_network_interface.vm01-ext-nic.id}"] 486 | vm_size = "${var.instance_type}" 487 | 488 | # Uncomment this line to delete the OS disk automatically when deleting the VM 489 | delete_os_disk_on_termination = true 490 | 491 | 492 | # Uncomment this line to delete the data disks automatically when deleting the VM 493 | delete_data_disks_on_termination = true 494 | 495 | storage_image_reference { 496 | publisher = "f5-networks" 497 | offer = "${var.product}" 498 | sku = "${var.image_name}" 499 | version = "${var.bigip_version}" 500 | } 501 | 502 | storage_os_disk { 503 | name = "${var.prefix}vm01-osdisk" 504 | caching = "ReadWrite" 505 | create_option = "FromImage" 506 | managed_disk_type = "Standard_LRS" 507 | } 508 | 509 | os_profile { 510 | computer_name = "${var.prefix}vm01" 511 | admin_username = "${var.uname}" 512 | admin_password = "${var.upassword}" 513 | custom_data = "${data.template_file.vm_onboard.rendered}" 514 | } 515 | 516 | os_profile_linux_config { 517 | disable_password_authentication = false 518 | } 519 | 520 | plan { 521 | name = "${var.image_name}" 522 | publisher = "f5-networks" 523 | product = "${var.product}" 524 | } 525 | 526 | boot_diagnostics { 527 | enabled = "true" 528 | storage_uri = "${azurerm_storage_account.mystorage.primary_blob_endpoint}" 529 | } 530 | 531 | identity { 532 | type = "SystemAssigned" 533 | } 534 | 535 | tags = { 536 | Name = "${var.environment}-f5vm01" 537 | environment = "${var.environment}" 538 | owner = "${var.owner}" 539 | group = "${var.group}" 540 | costcenter = "${var.costcenter}" 541 | application = "${var.application}" 542 | } 543 | } 544 | 545 | resource "azurerm_virtual_machine" "f5vm02" { 546 | name = "${var.prefix}-f5vm02" 547 | location = "${azurerm_resource_group.main.location}" 548 | zones = [2] 549 | resource_group_name = "${azurerm_resource_group.main.name}" 550 | primary_network_interface_id = "${azurerm_network_interface.vm02-mgmt-nic.id}" 551 | network_interface_ids = ["${azurerm_network_interface.vm02-mgmt-nic.id}", "${azurerm_network_interface.vm02-ext-nic.id}"] 552 | vm_size = "${var.instance_type}" 553 | 554 | # Uncomment this line to delete the OS disk automatically when deleting the VM 555 | delete_os_disk_on_termination = true 556 | 557 | 558 | # Uncomment this line to delete the data disks automatically when deleting the VM 559 | delete_data_disks_on_termination = true 560 | 561 | storage_image_reference { 562 | publisher = "f5-networks" 563 | offer = "${var.product}" 564 | sku = "${var.image_name}" 565 | version = "${var.bigip_version}" 566 | } 567 | 568 | storage_os_disk { 569 | name = "${var.prefix}vm02-osdisk" 570 | caching = "ReadWrite" 571 | create_option = "FromImage" 572 | managed_disk_type = "Standard_LRS" 573 | } 574 | 575 | os_profile { 576 | computer_name = "${var.prefix}vm02" 577 | admin_username = "${var.uname}" 578 | admin_password = "${var.upassword}" 579 | custom_data = "${data.template_file.vm_onboard.rendered}" 580 | } 581 | 582 | os_profile_linux_config { 583 | disable_password_authentication = false 584 | } 585 | 586 | plan { 587 | name = "${var.image_name}" 588 | publisher = "f5-networks" 589 | product = "${var.product}" 590 | } 591 | 592 | boot_diagnostics { 593 | enabled = "true" 594 | storage_uri = "${azurerm_storage_account.mystorage.primary_blob_endpoint}" 595 | } 596 | 597 | identity { 598 | type = "SystemAssigned" 599 | } 600 | 601 | tags = { 602 | Name = "${var.environment}-f5vm02" 603 | environment = "${var.environment}" 604 | owner = "${var.owner}" 605 | group = "${var.group}" 606 | costcenter = "${var.costcenter}" 607 | application = "${var.application}" 608 | } 609 | } 610 | 611 | # backend VM 612 | resource "azurerm_virtual_machine" "backendvm" { 613 | name = "backendvm" 614 | location = "${azurerm_resource_group.main.location}" 615 | resource_group_name = "${azurerm_resource_group.main.name}" 616 | 617 | network_interface_ids = ["${azurerm_network_interface.backend01-ext-nic.id}"] 618 | vm_size = "Standard_DS1_v2" 619 | 620 | storage_os_disk { 621 | name = "backendOsDisk" 622 | caching = "ReadWrite" 623 | create_option = "FromImage" 624 | managed_disk_type = "Premium_LRS" 625 | } 626 | 627 | storage_image_reference { 628 | publisher = "Canonical" 629 | offer = "UbuntuServer" 630 | sku = "16.04.0-LTS" 631 | version = "latest" 632 | } 633 | 634 | os_profile { 635 | computer_name = "backend01" 636 | admin_username = "azureuser" 637 | admin_password = "${var.upassword}" 638 | custom_data = <<-EOF 639 | #!/bin/bash 640 | apt-get update -y 641 | apt-get install -y docker.io 642 | docker run -d -p 80:80 --net=host --restart unless-stopped vulnerables/web-dvwa 643 | EOF 644 | } 645 | 646 | os_profile_linux_config { 647 | disable_password_authentication = false 648 | } 649 | 650 | tags = { 651 | Name = "${var.environment}-backend01" 652 | environment = "${var.environment}" 653 | owner = "${var.owner}" 654 | group = "${var.group}" 655 | costcenter = "${var.costcenter}" 656 | } 657 | } 658 | 659 | 660 | # Configure VMs to use a system-assgined managed identity 661 | data "azurerm_resource_group" "main" { 662 | name = "${azurerm_resource_group.main.name}" 663 | depends_on = ["azurerm_virtual_machine.f5vm01", "azurerm_virtual_machine.f5vm02"] 664 | } 665 | 666 | data "azurerm_subscription" "primary" {} 667 | 668 | resource "azurerm_role_assignment" "f5vm01ra" { 669 | scope = "${data.azurerm_resource_group.main.id}" 670 | role_definition_name = "Contributor" 671 | principal_id = "${lookup(azurerm_virtual_machine.f5vm01.identity[0], "principal_id")}" 672 | } 673 | 674 | resource "azurerm_role_assignment" "f5vm02ra" { 675 | scope = "${data.azurerm_resource_group.main.id}" 676 | role_definition_name = "Contributor" 677 | principal_id = "${lookup(azurerm_virtual_machine.f5vm02.identity[0], "principal_id")}" 678 | } 679 | 680 | 681 | # Run Startup Script 682 | resource "azurerm_virtual_machine_extension" "f5vm01-run-startup-cmd" { 683 | name = "${var.environment}-f5vm01-run-startup-cmd" 684 | depends_on = ["azurerm_virtual_machine.f5vm01", "azurerm_virtual_machine.backendvm"] 685 | location = "${var.region}" 686 | resource_group_name = "${azurerm_resource_group.main.name}" 687 | virtual_machine_name = "${azurerm_virtual_machine.f5vm01.name}" 688 | publisher = "Microsoft.OSTCExtensions" 689 | type = "CustomScriptForLinux" 690 | type_handler_version = "1.2" 691 | # publisher = "Microsoft.Azure.Extensions" 692 | # type = "CustomScript" 693 | # type_handler_version = "2.0" 694 | 695 | settings = <>$LOG_FILE 11 | else 12 | #if file exists, exit as only want to run once 13 | exit 14 | fi 15 | 16 | exec 1>$LOG_FILE 2>&1 17 | 18 | # CHECK TO SEE NETWORK IS READY 19 | CNT=0 20 | while true 21 | do 22 | STATUS=$(curl -s -k -I example.com | grep HTTP) 23 | if [[ $STATUS == *"200"* ]]; then 24 | echo "Got 200! VE is Ready!" 25 | break 26 | elif [ $CNT -le 6 ]; then 27 | echo "Status code: $STATUS Not done yet..." 28 | CNT=$[$CNT+1] 29 | else 30 | echo "GIVE UP..." 31 | break 32 | fi 33 | sleep 10 34 | done 35 | 36 | sleep 60 37 | 38 | tmsh modify sys db config.allow.rfc3927 value enable 39 | tmsh create sys management-route fometa_route network 169.254.169.254/32 gateway '${mgmt_gw}' 40 | tmsh save sys config 41 | 42 | ### DOWNLOAD ONBOARDING PKGS 43 | # Could be pre-packaged or hosted internally 44 | 45 | admin_username='${uname}' 46 | admin_password='${upassword}' 47 | CREDS="admin:"$admin_password 48 | DO_URL='${DO_onboard_URL}' 49 | DO_FN=$(basename "$DO_URL") 50 | AS3_URL='${AS3_URL}' 51 | AS3_FN=$(basename "$AS3_URL") 52 | TS_URL='${TS_URL}' 53 | TS_FN=$(basename "$TS_URL") 54 | CF_URL='${CF_URL}' 55 | CF_FN=$(basename "$CF_URL") 56 | 57 | 58 | mkdir -p ${libs_dir} 59 | 60 | echo -e "\n"$(date) "Download TS Pkg" 61 | curl -L -k -o ${libs_dir}/$TS_FN $TS_URL 62 | 63 | echo -e "\n"$(date) "Download Declarative Onboarding Pkg" 64 | curl -L -k -o ${libs_dir}/$DO_FN $DO_URL 65 | 66 | echo -e "\n"$(date) "Download AS3 Pkg" 67 | curl -L -k -o ${libs_dir}/$AS3_FN $AS3_URL 68 | 69 | echo -e "\n"$(date) "Download CF Pkg" 70 | curl -L -k -o ${libs_dir}/$CF_FN $CF_URL 71 | sleep 20 72 | 73 | # Copy the RPM Pkg to the file location 74 | cp ${libs_dir}/*.rpm /var/config/rest/downloads/ 75 | 76 | # Install Telemetry Streaming Pkg 77 | DATA="{\"operation\":\"INSTALL\",\"packageFilePath\":\"/var/config/rest/downloads/$TS_FN\"}" 78 | echo -e "\n"$(date) "Install TS Pkg" 79 | curl -u $CREDS -X POST http://localhost:8100/mgmt/shared/iapp/package-management-tasks -d $DATA 80 | 81 | sleep 10 82 | 83 | # Install Declarative Onboarding Pkg 84 | DATA="{\"operation\":\"INSTALL\",\"packageFilePath\":\"/var/config/rest/downloads/$DO_FN\"}" 85 | echo -e "\n"$(date) "Install DO Pkg" 86 | curl -u $CREDS -X POST http://localhost:8100/mgmt/shared/iapp/package-management-tasks -d $DATA 87 | 88 | sleep 10 89 | 90 | # Install AS3 Pkg 91 | DATA="{\"operation\":\"INSTALL\",\"packageFilePath\":\"/var/config/rest/downloads/$AS3_FN\"}" 92 | echo -e "\n"$(date) "Install AS3 Pkg" 93 | curl -u $CREDS -X POST http://localhost:8100/mgmt/shared/iapp/package-management-tasks -d $DATA 94 | 95 | sleep 10 96 | 97 | # Install CF Pkg 98 | DATA="{\"operation\":\"INSTALL\",\"packageFilePath\":\"/var/config/rest/downloads/$CF_FN\"}" 99 | echo -e "\n"$(date) "Install CF Pkg" 100 | curl -u $CREDS -X POST http://localhost:8100/mgmt/shared/iapp/package-management-tasks -d $DATA 101 | 102 | sleep 10 103 | 104 | # Check DO Ready 105 | CNT=0 106 | while true 107 | do 108 | STATUS=$(curl -u $CREDS -X GET -s -k -I https://localhost/mgmt/shared/declarative-onboarding | grep HTTP) 109 | if [[ $STATUS == *"200"* ]]; then 110 | echo "Got 200! Declarative Onboarding is Ready!" 111 | break 112 | elif [ $CNT -le 6 ]; then 113 | echo "Status code: $STATUS DO Not done yet..." 114 | CNT=$[$CNT+1] 115 | else 116 | echo "GIVE UP..." 117 | break 118 | fi 119 | sleep 10 120 | done 121 | 122 | # Check AS3 Ready 123 | CNT=0 124 | while true 125 | do 126 | STATUS=$(curl -u $CREDS -X GET -s -k -I https://localhost/mgmt/shared/appsvcs/info | grep HTTP) 127 | if [[ $STATUS == *"200"* ]]; then 128 | echo "Got 200! AS3 is Ready!" 129 | break 130 | elif [ $CNT -le 6 ]; then 131 | echo "Status code: $STATUS AS3 Not done yet..." 132 | CNT=$[$CNT+1] 133 | else 134 | echo "GIVE UP..." 135 | break 136 | fi 137 | sleep 10 138 | done 139 | 140 | # Check TS Ready 141 | CNT=0 142 | while true 143 | do 144 | STATUS=$(curl -u $CREDS -X GET -s -k -I https://localhost/mgmt/shared/telemetry/declare | grep HTTP) 145 | if [[ $STATUS == *"200"* ]]; then 146 | echo "Got 200! TS is Ready!" 147 | break 148 | elif [ $CNT -le 6 ]; then 149 | echo "Status code: $STATUS TS Not done yet..." 150 | CNT=$[$CNT+1] 151 | else 152 | echo "GIVE UP..." 153 | break 154 | fi 155 | sleep 10 156 | done 157 | 158 | # Check CF Ready 159 | CNT=0 160 | while true 161 | do 162 | STATUS=$(curl -u $CREDS -X GET -s -k -I https://localhost/mgmt/shared/cloud-failover/info | grep HTTP) 163 | if [[ $STATUS == *"200"* ]]; then 164 | echo "Got 200! TS is Ready!" 165 | break 166 | elif [ $CNT -le 6 ]; then 167 | echo "Status code: $STATUS TS Not done yet..." 168 | CNT=$[$CNT+1] 169 | else 170 | echo "GIVE UP..." 171 | break 172 | fi 173 | sleep 10 174 | done 175 | 176 | sleep 60 177 | -------------------------------------------------------------------------------- /HA_via_api/provider.tf: -------------------------------------------------------------------------------- 1 | # Configure the Microsoft Azure Provider, replace Service Principal and Subscription with your own 2 | provider "azurerm" { 3 | subscription_id = "${var.SP["subscription_id"]}" 4 | client_id = "${var.SP["client_id"]}" 5 | client_secret = "${var.SP["client_secret"]}" 6 | tenant_id = "${var.SP["tenant_id"]}" 7 | } 8 | 9 | -------------------------------------------------------------------------------- /HA_via_api/variables.tf: -------------------------------------------------------------------------------- 1 | # REST API Setting 2 | variable rest_do_uri { default = "/mgmt/shared/declarative-onboarding" } 3 | variable rest_as3_uri { default = "/mgmt/shared/appsvcs/declare" } 4 | variable rest_CF_uri { default = "/mgmt/shared/cloud-failover/declare" } 5 | variable rest_do_method { default = "POST" } 6 | variable rest_as3_method { default = "POST" } 7 | variable rest_vm01_do_file {default = "vm01_do_data.json" } 8 | variable rest_vm02_do_file {default = "vm02_do_data.json" } 9 | variable rest_vm_as3_file {default = "vm_as3_data.json" } 10 | variable rest_vm_failover_file {default = "vm_failover_data.json" } 11 | 12 | # Azure Environment 13 | variable "SP" { 14 | type = "map" 15 | default = { 16 | subscription_id = "xxxxx" 17 | client_id = "xxxxx" 18 | client_secret = "xxxxx" 19 | tenant_id = "xxxxx" 20 | } 21 | } 22 | variable prefix { default = "zludemo" } 23 | variable uname { default = "azureuser" } 24 | variable upassword { default = "Default12345" } 25 | variable location { default = "eastus" } 26 | variable region { default = "East US" } 27 | 28 | # NETWORK 29 | variable cidr { default = "10.90.0.0/16" } 30 | variable "subnets" { 31 | type = "map" 32 | default = { 33 | "subnet1" = "10.90.1.0/24" 34 | "subnet2" = "10.90.2.0/24" 35 | "subnet3" = "10.90.3.0/24" 36 | } 37 | } 38 | variable managed_route1 { default = "0.0.0.0/0" } 39 | variable f5vm01mgmt { default = "10.90.1.4" } 40 | variable f5vm01ext { default = "10.90.2.4" } 41 | variable f5vm02mgmt { default = "10.90.1.5" } 42 | variable f5vm02ext { default = "10.90.2.5" } 43 | variable f5privatevip { default = "10.90.2.11" } 44 | variable f5publicvip { default = "10.90.2.12" } 45 | variable backend01ext { default = "10.90.2.101" } 46 | 47 | # BIGIP Image 48 | variable instance_type { default = "Standard_DS4_v2" } 49 | variable image_name { default = "f5-bigip-virtual-edition-25m-best-hourly" } 50 | variable product { default = "f5-big-ip-best" } 51 | variable bigip_version { default = "latest" } 52 | 53 | # BIGIP Setup 54 | variable license1 { default = ""} 55 | variable license2 { default = ""} 56 | variable host1_name { default = "f5vm01"} 57 | variable host2_name { default = "f5vm02"} 58 | variable dns_server { default = "8.8.8.8" } 59 | variable ntp_server { default = "0.us.pool.ntp.org" } 60 | variable timezone { default = "UTC" } 61 | ## Please check and update the latest DO URL from https://github.com/F5Networks/f5-declarative-onboarding/releases 62 | variable DO_onboard_URL { default = "https://github.com/garyluf5/f5tools/raw/master/f5-declarative-onboarding-1.7.0-3.noarch.rpm" } 63 | ## Please check and update the latest AS3 URL from https://github.com/F5Networks/f5-appsvcs-extension/releases/latest 64 | variable AS3_URL { default = "https://github.com/garyluf5/f5tools/raw/master/f5-appsvcs-3.14.0-4.noarch.rpm" } 65 | ## Please check and update the latest Telemtry URL from https://github.com/F5Networks/f5-telemetry-streaming/tree/master/dist 66 | variable TS_URL { default = "https://github.com/garyluf5/f5tools/raw/master/f5-telemetry-1.5.0-1.noarch.rpm" } 67 | ## Please check and update the latest Cloud Failover RPM URL from https://clouddocs.f5networks.net/products/extensions/f5-cloud-failover/latest/ 68 | variable CF_URL { default = "https://github.com/f5devcentral/f5-cloud-failover-extension/releases/download/v0.9.1/f5-cloud-failover-0.9.1-1.noarch.rpm" } 69 | variable libs_dir { default = "/config/cloud/azure/node_modules" } 70 | variable onboard_log { default = "/var/log/startup-script.log" } 71 | 72 | # TAGS 73 | variable purpose { default = "public" } 74 | variable environment { default = "f5env" } #ex. dev/staging/prod 75 | variable owner { default = "f5owner" } 76 | variable group { default = "f5group" } 77 | variable costcenter { default = "f5costcenter" } 78 | variable application { default = "f5app" } 79 | variable f5_cloud_failover_label { default = "mydeployment" } #Cloud Failover Tag 80 | variable f5_cloud_failover_nic_map { default = "external" } #NIC Tag 81 | 82 | 83 | -------------------------------------------------------------------------------- /HA_via_lb_DO_AS3/.terraform/plugins/linux_386/lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "azurerm": "89a398e5af9cd0897610fa54b267df526ab08f7651fe593cab9c99a9edee4bda", 3 | "template": "f744d30b973c50a5a3ff20c27e4dddccea8447c5d4758b0ef23af31d05b1db00" 4 | } -------------------------------------------------------------------------------- /HA_via_lb_DO_AS3/.terraform/plugins/linux_386/terraform-provider-azurerm_v1.21.0_x4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garyluf5/f5_terraform/ab4ceb4c754d507d4db96b30cbb75ac53e30d61f/HA_via_lb_DO_AS3/.terraform/plugins/linux_386/terraform-provider-azurerm_v1.21.0_x4 -------------------------------------------------------------------------------- /HA_via_lb_DO_AS3/.terraform/plugins/linux_386/terraform-provider-template_v2.0.0_x4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garyluf5/f5_terraform/ab4ceb4c754d507d4db96b30cbb75ac53e30d61f/HA_via_lb_DO_AS3/.terraform/plugins/linux_386/terraform-provider-template_v2.0.0_x4 -------------------------------------------------------------------------------- /HA_via_lb_DO_AS3/HA_via_lb_2nics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garyluf5/f5_terraform/ab4ceb4c754d507d4db96b30cbb75ac53e30d61f/HA_via_lb_DO_AS3/HA_via_lb_2nics.png -------------------------------------------------------------------------------- /HA_via_lb_DO_AS3/README.md: -------------------------------------------------------------------------------- 1 | # Deploying BIG-IP VEs in Azure - ConfigSync Cluster (Active/Standby): Two NICs 2 | 3 | ## Contents 4 | 5 | - [Introduction](#introduction) 6 | - [Prerequisites](#prerequisites) 7 | - [Important Configuration Notes](#important-configuration-notes) 8 | - [Security](#security) 9 | - [Configuration Example](#configuration-example) 10 | 11 | ## Introduction 12 | 13 | This solution uses an Terraform template to launch a two NIC deployment of a cloud-focused BIG-IP VE cluster (Active/Standby) in Microsoft Azure. Traffic flows from an ALB to the BIG-IP VE which then processes the traffic to application servers. This is the standard cloud design where the BIG-IP VE instance is running with a dual interface, where both management and data plane traffic is processed on each one. 14 | 15 | The BIG-IP VEs have the [Local Traffic Manager (LTM)](https://f5.com/products/big-ip/local-traffic-manager-ltm) module enabled to provide advanced traffic management functionality. This means you can also configure the BIG-IP VE to enable F5's L4/L7 security features, access control, and intelligent traffic management. 16 | 17 | The one big thing in this Terraform accounted for is composing resources a bit differently to account for dependencies into Immutable/Mutable elements. i.e. stuff you would typically frequently change/mutate, such as traditional config on the BIG-IP. Once the template is deployed, there are certain resources (like the network infrastructure) that are fixed while others (like BIG-IP VMs and configurations) can be changed 18 | Ex. 19 | -> Run once 20 | - Deploy the entire infrastructure with all the neccessary resources, then we use Declarative Onboarding to configure the BIG-IP Cluster; AS3 to create a sample app proxy; then lastly use Service Discovery automatically add the DVWA container app to the LTM pool (Please note currently we also hardcode the node IP in the pool due to a bug in our AS3, which will be fixed in the next release) 21 | 22 | -> Run many X 23 | - [Redeploy BIG-IP for replacement or upgrade](#Redeploy-BIG-IP-for-replacement-or-upgrade) 24 | - [Reconfigure BIG-IP configurations](#Rerun-AS3-on-the-big-ip-ve) 25 | 26 | **Networking Stack Type:** This solution deploys into a new networking stack, which is created along with the solution. 27 | 28 | ## Prerequisites 29 | 30 | - **Important**: When you configure the admin password for the BIG-IP VE in the template, you cannot use the character **#**. Additionally, there are a number of other special characters that you should avoid using for F5 product user accounts. See [K2873](https://support.f5.com/csp/article/K2873) for details. 31 | - This template requires a service principal. See the [Service Principal Setup section](#service-principal-authentication) for details, including required permissions. 32 | - This deployment will be using the Terraform Azurerm provider to build out all the neccessary Azure objects. Therefore, Azure CLI is required. for installation, please follow this [Microsoft link](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-apt?view=azure-cli-latest) 33 | - If this is the first time to deploy the F5 image, the subscription used in this deployment needs to be enabled to programatically deploy. For more information, please refer to [Configure Programatic Deployment](https://azure.microsoft.com/en-us/blog/working-with-marketplace-images-on-azure-resource-manager/) 34 | 35 | ## Important configuration notes 36 | 37 | - All variables are configured in variables.tf 38 | - Azure Subscription and Service Principal are configured in provider.tf 39 | - This template would require Declarative Onboarding and AS3 packages for the initial configuration. As part of the onboarding script, it will download the RPMs respectively. So please see the [AS3 documentation](https://clouddocs.f5.com/products/extensions/f5-appsvcs-extension/3.5.1/) and [DO documentation](https://clouddocs.f5.com/products/extensions/f5-declarative-onboarding/latest/prereqs.html) for details on how to use AS3 and Declarative Onboarding on your BIG-IP VE(s). 40 | - onboard.tpl is the onboarding script, which is run by commandToExecute, and it will be copy to /var/lib/waagent/CustomData upon bootup. This script is basically responsible for downloading the neccessary DO and AS3 RPM files, installing them, and then executing the onboarding REST calls. 41 | - This template uses PayGo BIGIP image for the deployment (as default). If you would like to use BYOL, then these following steps are needed: 42 | 1. In the "variables.tf", specify the BYOL image and licenses regkeys. 43 | 2. In the "main.tf", uncomment the "local_sku" lines. 44 | 3. Add the following lines to the "cluster.json" file just under the "Common" declaration: 45 | ``` 46 | "myLicense": { 47 | "class": "License", 48 | "licenseType": "regKey", 49 | "regKey": "${local_sku}" 50 | }, 51 | ``` 52 | - In order to pass traffic from your clients to the servers, after launching the template, you must create virtual server(s) on the BIG-IP VE. See [Creating a virtual server](#creating-virtual-servers-on-the-big-ip-ve). 53 | - See the **[Configuration Example](#configuration-example)** section for a configuration diagram and description for this solution. 54 | 55 | ### Template parameters 56 | 57 | | Parameter | Required | Description | 58 | | --- | --- | --- | 59 | | prefix | Yes | This value is insert in the beginning of each Azure object, try keeps it alpha-numeric without any special character | 60 | | rest_do_uri | Yes | URI of the Declarative Onboarding REST call. | 61 | | rest_as3_uri | Yes | URI of the AS3 REST call. | 62 | | rest_do_method | Yes | Available options are GET, POST, and DELETE. | 63 | | rest_AS3_method | Yes | Available options are GET, POST, and DELETE. | 64 | | rest_vm01_do_file | Yes | Terraform will generate the vm01 DO json file, where you can manually run it again for debugging. | 65 | | rest_vm02_do_file | Yes | Terraform will generate the vm02 DO json file, where you can manually run it again for debugging. | 66 | | rest_vm_as3_file | Yes | Terraform will generate the AS3 json file, where you can manually run it again for debugging. | 67 | | SP | YES | This is the service principal of your Azure subscription. | 68 | | uname | Yes | User name for the Virtual Machine. | 69 | | upassword | Yes | Password for the Virtual Machine. | 70 | | location | Yes | Location of the deployment. | 71 | | region | Yes | Region of the deployment. | 72 | | cidr | Yes | IP Address range of the Virtual Network. | 73 | | subnet1 | Yes | Subnet IP range of the management network. | 74 | | subnet2 | Yes | Subnet IP range of the external network. | 75 | | subnet3 | No | Subnet IP range of the internal network. | 76 | | f5vm01mgmt | Yes | IP address for 1st BIG-IP's management interface. | 77 | | f5vm02mgmt | Yes | IP address for 2nd BIG-IP's management interface. | 78 | | f5vm01ext | Yes | IP address for 1st BIG-IP's external interface. | 79 | | f5vm01ext_sec | Yes | Secondary IP address for 1st BIG-IP's external interface. | 80 | | f5vm02ext | Yes | IP address for 2nd BIG-IP's external interface. | 81 | | f5vm02ext_sec | Yes | Secondary IP address for 2nd BIG-IP's external interface. | 82 | | instance_type | Yes | Azure instance to be used for the BIG-IP VE. | 83 | | product | Yes | Azure BIG-IP VE Offer. | 84 | | bigip_version | Yes | It is set to default to use the latest software. | 85 | | image_name | Yes | F5 SKU (image) to you want to deploy. Note: The disk size of the VM will be determined based on the option you select. **Important**: If intending to provision multiple modules, ensure the appropriate value is selected, such as ****AllTwoBootLocations or AllOneBootLocation****. | 86 | | license1 | No | The license token for the F5 BIG-IP VE (BYOL). | 87 | | license2 | No | The license token for the F5 BIG-IP VE (BYOL). | 88 | | host1_name | Yes | Hostname for the 1st BIG-IP. | 89 | | host2_name | Yes | Hostname for the 2nd BIG-IP. | 90 | | ntp_server | Yes | Leave the default NTP server the BIG-IP uses, or replace the default NTP server with the one you want to use. | 91 | | timezone | Yes | If you would like to change the time zone the BIG-IP uses, enter the time zone you want to use. This is based on the tz database found in /usr/share/zoneinfo (see the full list [here](https://github.com/F5Networks/f5-azure-arm-templates/blob/master/azure-timezone-list.md)). Example values: UTC, US/Pacific, US/Eastern, Europe/London or Asia/Singapore. | 92 | | dns_server | Yes | Least the default DNS server the BIG-IP uses, or replace the default DNS server with the one you want to use. | 93 | | DO_onboard_URL | Yes | This is the raw github URL for downloading the Declarative Onboarding RPM | 94 | | AS3_URL | Yes | This is the raw github URL for downloading the AS3 RPM. | 95 | | libs_dir | Yes | This is where all the temporary libs and RPM will be store in BIG-IP. | 96 | | onboard_log | Yes | This is where the onboarding script logs all the events. | 97 | 98 | 99 | ## Configuration Example 100 | 101 | The following is an example configuration diagram for this solution deployment. In this scenario, all access to the BIG-IP VE cluster (Active/Standby) is through an ALB. The IP addresses in this example may be different in your implementation. 102 | 103 | ![Configuration Example](./HA_via_lb_2nics.png) 104 | 105 | 106 | ## Documentation 107 | 108 | For more information on F5 solutions for Azure, including manual configuration procedures for some deployment scenarios, see the Azure section of [Public Cloud Docs](http://clouddocs.f5.com/cloud/public/v1/). 109 | 110 | ## Creating virtual servers on the BIG-IP VE 111 | 112 | In order to pass traffic from your clients to the servers through the BIG-IP system, you must create a virtual server on the BIG-IP VE. 113 | 114 | In this template, the Azure public IP address is associated with an Azure Load Balancer that forwards traffic to a backend pool that includes the primary (self) IP configurations for *each* BIG-IP network interface. Because traffic is destined for the self IP addresses of the BIG-IP VEs, you must create a single virtual server with a wildcard destination in Traffic Group **None**. 115 | 116 | 1. Once your BIG-IP VE has launched, open the BIG-IP VE Configuration utility. 117 | 2. On the Main tab, click **Local Traffic > Virtual Servers** and then click the **Create** button. 118 | 3. In the **Name** field, give the Virtual Server a unique name. 119 | 4. In the **Destination/Mask** field, type the destination address ( for example: 0.0.0.0/0). 120 | 5. In the **Service Port** field, type the appropriate port. 121 | 6. Configure the rest of the virtual server as appropriate. 122 | 7. If you used the Service Discovery iApp template: In the Resources section, from the **Default Pool** list, select the name of the pool created by the iApp. 123 | 8. Click the **Finished** button. 124 | 9. Repeat as necessary. 125 | 126 | When you have completed the virtual server configuration, you must modify the virtual addresses to use Traffic Group None using the following guidance. 127 | 128 | 1. On the Main tab, click **Local Traffic > Virtual Servers**. 129 | 2. On the Menu bar, click the **Virtual Address List** tab. 130 | 3. Click the address of one of the virtual servers you just created. 131 | 4. From the **Traffic Group** list, select **None**. 132 | 5. Click **Update**. 133 | 6. Repeat for each virtual server. 134 | 135 | ## Redeploy BIG-IP for replacement or upgrade 136 | This example illustrates how to replace the BIG-IP VE 137 | 1. Revoke the problematic BIG-IP VE's license 138 | 2. Run command 139 | ``` 140 | terraform destroy -target azurerm_virtual_machine.f5vm02 141 | ``` 142 | 3. Run command 143 | ``` 144 | terraform apply 145 | ``` 146 | 4. At this time, you have 2 standalone BIG-IP VEs behind the Azure LB, which is fine. Repeate step 1 to step 3 on the other BIG-IP VE otherwise, the Device Trust won't be configured correctly 147 | 148 | 149 | This example illustrate how to upgrade the BIG-IP VEs (remember, when replace a VE, we replace both, can't be just single VE) 150 | 1. Change the 'bigip_version' variable to the desired release 151 | 2. Revoke the problematic BIG-IP VE's license 152 | 3. Run command 153 | ``` 154 | terraform destroy -target azurerm_virtual_machine.f5vm02 155 | ``` 156 | 4. Run command 157 | ``` 158 | terraform apply 159 | ``` 160 | 5. At this time, you have 2 standalone BIG-IP VEs behind the Azure LB, which is fine. Repeate step 2 to step 4 on the other BIG-IP VE otherwise, the Device Trust won't be configured correctly 161 | 162 | ## Rerun AS3 on the Big-ip ve 163 | - This example illustrate how to run your own custom AS3, you can have a catalog of AS3 and repeat this steps as many times as desired 164 | ``` 165 | terraform taint null_resource.f5vm02-run-REST 166 | terraform apply -target null_resource.f5vm02-run-REST -var "rest_do_method=GET" -var "rest_as3_method=POST" -var "rest_vm_as3_file=test.json" -var "rest_vm02_do_file=''" 167 | ``` 168 | - If you would like to re-run your DO json, just swap the above REST methods, and apply the new DO json file, then you can repeat the above steps as many time as you'd need. 169 | -------------------------------------------------------------------------------- /HA_via_lb_DO_AS3/as3.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "AS3", 3 | "action": "deploy", 4 | "persist": true, 5 | "declaration": { 6 | "class": "ADC", 7 | "schemaVersion": "3.0.0", 8 | "id": "123abc", 9 | "label": "Sample 1", 10 | "remark": "HTTPS with predictive-node pool", 11 | "Sample_01": { 12 | "class": "Tenant", 13 | "Shared": { 14 | "class":"Application", 15 | "template":"shared", 16 | "serviceAddress": { 17 | "class":"Service_Address", 18 | "virtualAddress":"0.0.0.0"} 19 | }, 20 | "A1": { 21 | "class": "Application", 22 | "template": "https", 23 | "serviceMain": { 24 | "class": "Service_HTTPS", 25 | "virtualPort": 8443, 26 | "virtualAddresses": [{ 27 | "use":"/Sample_01/Shared/serviceAddress" 28 | }], 29 | "pool": "web_pool", 30 | "serverTLS": "webtls" 31 | }, 32 | "web_pool": { 33 | "class": "Pool", 34 | "loadBalancingMode": "predictive-node", 35 | "members": [{ 36 | "servicePort": 80, 37 | "addressDiscovery": "azure", 38 | "updateInterval": 10, 39 | "tagKey": "application", 40 | "tagValue": "app1", 41 | "addressRealm": "private", 42 | "resourceGroup": "${rg_name}", 43 | "subscriptionId": "${subscription_id}", 44 | "directoryId": "${tenant_id}", 45 | "applicationId": "${client_id}", 46 | "apiAccessKey": "${client_secret}", 47 | "credentialUpdate": false 48 | }] 49 | }, 50 | "webtls": { 51 | "class": "TLS_Server", 52 | "certificates": [{ 53 | "certificate": "webcert" 54 | }] 55 | }, 56 | "webcert": { 57 | "class": "Certificate", 58 | "remark": "in practice we recommend using a passphrase", 59 | "certificate": "-----BEGIN CERTIFICATE-----\nMIICnDCCAgWgAwIBAgIJAJ5n2b0OCEjwMA0GCSqGSIb3DQEBCwUAMGcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMRQwEgYDVQQKDAtmNV9OZXR3b3JrczEbMBkGA1UEAwwSc2FtcGxlLmV4YW1wbGUubmV0MB4XDTE3MTEyNjE5NTAyNFoXDTE4MDIyNTE5NTAyNFowZzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxFDASBgNVBAoMC2Y1X05ldHdvcmtzMRswGQYDVQQDDBJzYW1wbGUuZXhhbXBsZS5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALEsuXmSXVQpYjrZPW+WiTBjn491mwZYT7Q92V1HlSBtM6WdWlK1aZN5sovfKtOX7Yrm8xa+e4o/zJ2QYLyyv5O+t2EGN/4qUEjEAPY9mwJdfzRQy6Hyzm84J0QkTuUJ/EjNuPji3D0QJRALUTzu1UqqDCEtiN9OGyXEkh7uvb7BAgMBAAGjUDBOMB0GA1UdDgQWBBSVHPNrGWrjWyZvckQxFYWO59FRFjAfBgNVHSMEGDAWgBSVHPNrGWrjWyZvckQxFYWO59FRFjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBAJeJ9SEckEwPhkXOm+IuqfbUS/RcziifBCTmVyE+Fa/j9pKSYTgiEBNdbJeBEa+gPMlQtbV7Y2dy8TKx/8axVBHiXC5geDML7caxOrAyHYBpnx690xJTh5OIORBBM/a/NvaR+P3CoVebr/NPRh9oRNxnntnqvqD7SW0U3ZPe3tJc\n-----END CERTIFICATE-----", 60 | "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-256-CBC,D8FFCE6B255601587CB54EC29B737D31\n\nkv4Fc3Jn0Ujkj0yRjt+gQQfBLSNF2aRLUENXnlr7Xpzqu0Ahr3jS1bAAnd8IWnsR\nyILqVmKsYF2DoHh0tWiEAQ7/y/fe5DTFhK7N4Wml6kp2yVMkP6KC4ssyYPw27kjK\nDBwBZ5O8Ioej08A5sgsLCmglbmtSPHJUn14pQnMTmLOpEtOsu6S+2ibPgSNpdg0b\nCAJNG/KHe+Vkx59qNDyDeKb7FZOlsX30+y67zUq9GQqJEDuysPJ2BUNP0IJXAjst\nFIt1qNoZew+5KDYs7u/lPxcMGTirUhgI84Jy4WcDvSOsP/tKlxj04TbIE3epmSKy\n+TihHkwY7ngIGtcm3Sfqk5jz2RXoj1/Ac3SW8kVTYaOUogBhn7zAq4Wju6Et4hQG\nRGapsJp1aCeZ/a4RCDTxspcKoMaRa97/URQb0hBRGx3DGUhzpmX9zl7JI2Xa5D3R\nmdBXtjLKYJTdIMdd27prBEKhMUpae2rz5Mw4J907wZeBq/wu+zp8LAnecfTe2nGY\nE32x1U7gSEdYOGqnwxsOexb1jKgCa67Nw9TmcMPV8zmH7R9qdvgxAbAtwBl1F9OS\nfcGaC7epf1AjJLtaX7krWmzgASHl28Ynh9lmGMdv+5QYMZvKG0LOg/n3m8uJ6sKy\nIzzvaJswwn0j5P5+czyoV5CvvdCfKnNb+3jUEN8I0PPwjBGKr4B1ojwhogTM248V\nHR69D6TxFVMfGpyJhCPkbGEGbpEpcffpgKuC/mEtMqyDQXJNaV5HO6HgAJ9F1P6v\n5ehHHTMRvzCCFiwndHdlMXUjqSNjww6me6dr6LiAPbejdzhL2vWx1YqebOcwQx3G\n-----END RSA PRIVATE KEY-----", 61 | "passphrase": { 62 | "ciphertext": "ZjVmNQ==", 63 | "protected": "eyJhbGciOiJkaXIiLCJlbmMiOiJub25lIn0" 64 | } 65 | } 66 | } 67 | } 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /HA_via_lb_DO_AS3/cluster.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0.0", 3 | "class": "Device", 4 | "label": "Basic onboarding", 5 | "Common": { 6 | "class": "Tenant", 7 | "hostname": "${local_host}.example.com", 8 | "dbvars": { 9 | "class": "DbVariables", 10 | "ui.advisory.enabled": true, 11 | "ui.advisory.color": "green", 12 | "ui.advisory.text": "/Common/hostname" 13 | }, 14 | "myDns": { 15 | "class": "DNS", 16 | "nameServers": [ 17 | "${dns_server}", 18 | "2001:4860:4860::8844" 19 | ], 20 | "search": [ 21 | "f5.com" 22 | ] 23 | }, 24 | "myNtp": { 25 | "class": "NTP", 26 | "servers": [ 27 | "${ntp_server}", 28 | "0.pool.ntp.org", 29 | "1.pool.ntp.org" 30 | ], 31 | "timezone": "${timezone}" 32 | }, 33 | "myProvisioning": { 34 | "class": "Provision", 35 | "ltm": "nominal" 36 | }, 37 | "external": { 38 | "class": "VLAN", 39 | "tag": 4094, 40 | "mtu": 1500, 41 | "interfaces": [ 42 | { 43 | "name": "1.1", 44 | "tagged": false 45 | } 46 | ] 47 | }, 48 | "external-self": { 49 | "class": "SelfIp", 50 | "address": "${local_selfip}/24", 51 | "vlan": "external", 52 | "allowService": "default", 53 | "trafficGroup": "traffic-group-local-only" 54 | }, 55 | "default": { 56 | "class": "Route", 57 | "gw": "${gateway}", 58 | "network": "default", 59 | "mtu": 1500 60 | }, 61 | "configsync": { 62 | "class": "ConfigSync", 63 | "configsyncIp": "/Common/external-self/address" 64 | }, 65 | "failoverAddress": { 66 | "class": "FailoverUnicast", 67 | "address": "/Common/external-self/address" 68 | }, 69 | "failoverGroup": { 70 | "class": "DeviceGroup", 71 | "type": "sync-failover", 72 | "members": ["${host1}.example.com", "${host2}.example.com"], 73 | "owner": "/Common/failoverGroup/members/0", 74 | "autoSync": true, 75 | "saveOnAutoSync": false, 76 | "networkFailover": true, 77 | "fullLoadOnSync": false, 78 | "asmSync": false 79 | }, 80 | "trust": { 81 | "class": "DeviceTrust", 82 | "localUsername": "${admin_user}", 83 | "localPassword": "${admin_password}", 84 | "remoteHost": "${remote_selfip}", 85 | "remoteUsername": "${admin_user}", 86 | "remotePassword": "${admin_password}" 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /HA_via_lb_DO_AS3/main.tf: -------------------------------------------------------------------------------- 1 | # Create a Resource Group for the new Virtual Machine 2 | resource "azurerm_resource_group" "main" { 3 | name = "${var.prefix}_rg" 4 | location = "${var.location}" 5 | } 6 | 7 | # Create a Virtual Network within the Resource Group 8 | resource "azurerm_virtual_network" "main" { 9 | name = "${var.prefix}-network" 10 | address_space = ["${var.cidr}"] 11 | resource_group_name = "${azurerm_resource_group.main.name}" 12 | location = "${azurerm_resource_group.main.location}" 13 | } 14 | 15 | # Create the first Subnet within the Virtual Network 16 | resource "azurerm_subnet" "Mgmt" { 17 | name = "Mgmt" 18 | virtual_network_name = "${azurerm_virtual_network.main.name}" 19 | resource_group_name = "${azurerm_resource_group.main.name}" 20 | address_prefix = "${var.subnets["subnet1"]}" 21 | } 22 | 23 | # Create the second Subnet within the Virtual Network 24 | resource "azurerm_subnet" "External" { 25 | name = "External" 26 | virtual_network_name = "${azurerm_virtual_network.main.name}" 27 | resource_group_name = "${azurerm_resource_group.main.name}" 28 | address_prefix = "${var.subnets["subnet2"]}" 29 | } 30 | 31 | # Obtain Gateway IP for each Subnet 32 | locals { 33 | depends_on = ["azurerm_subnet.Mgmt", "azurerm_subnet.External"] 34 | mgmt_gw = "${cidrhost(azurerm_subnet.Mgmt.address_prefix, 1)}" 35 | ext_gw = "${cidrhost(azurerm_subnet.External.address_prefix, 1)}" 36 | } 37 | 38 | # Create a Public IP for the Virtual Machines 39 | resource "azurerm_public_ip" "vm01mgmtpip" { 40 | name = "${var.prefix}-vm01-mgmt-pip" 41 | location = "${azurerm_resource_group.main.location}" 42 | resource_group_name = "${azurerm_resource_group.main.name}" 43 | allocation_method = "Dynamic" 44 | 45 | tags { 46 | Name = "${var.environment}-vm01-mgmt-public-ip" 47 | environment = "${var.environment}" 48 | owner = "${var.owner}" 49 | group = "${var.group}" 50 | costcenter = "${var.costcenter}" 51 | application = "${var.application}" 52 | } 53 | } 54 | 55 | resource "azurerm_public_ip" "vm02mgmtpip" { 56 | name = "${var.prefix}-vm02-mgmt-pip" 57 | location = "${azurerm_resource_group.main.location}" 58 | resource_group_name = "${azurerm_resource_group.main.name}" 59 | allocation_method = "Dynamic" 60 | 61 | tags { 62 | Name = "${var.environment}-vm02-mgmt-public-ip" 63 | environment = "${var.environment}" 64 | owner = "${var.owner}" 65 | group = "${var.group}" 66 | costcenter = "${var.costcenter}" 67 | application = "${var.application}" 68 | } 69 | } 70 | 71 | resource "azurerm_public_ip" "lbpip" { 72 | name = "${var.prefix}-lb-pip" 73 | location = "${azurerm_resource_group.main.location}" 74 | resource_group_name = "${azurerm_resource_group.main.name}" 75 | allocation_method = "Dynamic" 76 | domain_name_label = "${var.prefix}lbpip" 77 | } 78 | 79 | # Create Availability Set 80 | resource "azurerm_availability_set" "avset" { 81 | name = "${var.prefix}avset" 82 | location = "${azurerm_resource_group.main.location}" 83 | resource_group_name = "${azurerm_resource_group.main.name}" 84 | platform_fault_domain_count = 2 85 | platform_update_domain_count = 2 86 | managed = true 87 | } 88 | 89 | # Create Azure LB 90 | resource "azurerm_lb" "lb" { 91 | name = "${var.prefix}lb" 92 | location = "${azurerm_resource_group.main.location}" 93 | resource_group_name = "${azurerm_resource_group.main.name}" 94 | 95 | frontend_ip_configuration { 96 | name = "LoadBalancerFrontEnd" 97 | public_ip_address_id = "${azurerm_public_ip.lbpip.id}" 98 | } 99 | } 100 | 101 | resource "azurerm_lb_backend_address_pool" "backend_pool" { 102 | name = "BackendPool1" 103 | resource_group_name = "${azurerm_resource_group.main.name}" 104 | loadbalancer_id = "${azurerm_lb.lb.id}" 105 | } 106 | 107 | resource "azurerm_lb_probe" "lb_probe" { 108 | resource_group_name = "${azurerm_resource_group.main.name}" 109 | loadbalancer_id = "${azurerm_lb.lb.id}" 110 | name = "tcpProbe" 111 | protocol = "tcp" 112 | port = 8443 113 | interval_in_seconds = 5 114 | number_of_probes = 2 115 | } 116 | 117 | resource "azurerm_lb_rule" "lb_rule" { 118 | name = "LBRule" 119 | resource_group_name = "${azurerm_resource_group.main.name}" 120 | loadbalancer_id = "${azurerm_lb.lb.id}" 121 | protocol = "tcp" 122 | frontend_port = 443 123 | backend_port = 8443 124 | frontend_ip_configuration_name = "LoadBalancerFrontEnd" 125 | enable_floating_ip = false 126 | backend_address_pool_id = "${azurerm_lb_backend_address_pool.backend_pool.id}" 127 | idle_timeout_in_minutes = 5 128 | probe_id = "${azurerm_lb_probe.lb_probe.id}" 129 | depends_on = ["azurerm_lb_probe.lb_probe"] 130 | } 131 | 132 | # Create a Network Security Group with some rules 133 | resource "azurerm_network_security_group" "main" { 134 | name = "${var.prefix}-nsg" 135 | location = "${azurerm_resource_group.main.location}" 136 | resource_group_name = "${azurerm_resource_group.main.name}" 137 | 138 | security_rule { 139 | name = "allow_SSH" 140 | description = "Allow SSH access" 141 | priority = 100 142 | direction = "Inbound" 143 | access = "Allow" 144 | protocol = "Tcp" 145 | source_port_range = "*" 146 | destination_port_range = "22" 147 | source_address_prefix = "*" 148 | destination_address_prefix = "*" 149 | } 150 | 151 | security_rule { 152 | name = "allow_HTTP" 153 | description = "Allow HTTP access" 154 | priority = 110 155 | direction = "Inbound" 156 | access = "Allow" 157 | protocol = "Tcp" 158 | source_port_range = "*" 159 | destination_port_range = "80" 160 | source_address_prefix = "*" 161 | destination_address_prefix = "*" 162 | } 163 | 164 | security_rule { 165 | name = "allow_HTTPS" 166 | description = "Allow HTTPS access" 167 | priority = 120 168 | direction = "Inbound" 169 | access = "Allow" 170 | protocol = "Tcp" 171 | source_port_range = "*" 172 | destination_port_range = "443" 173 | source_address_prefix = "*" 174 | destination_address_prefix = "*" 175 | } 176 | 177 | security_rule { 178 | name = "allow_RDP" 179 | description = "Allow RDP access" 180 | priority = 130 181 | direction = "Inbound" 182 | access = "Allow" 183 | protocol = "Tcp" 184 | source_port_range = "*" 185 | destination_port_range = "3389" 186 | source_address_prefix = "*" 187 | destination_address_prefix = "*" 188 | } 189 | 190 | security_rule { 191 | name = "allow_APP_HTTPS" 192 | description = "Allow HTTPS access" 193 | priority = 140 194 | direction = "Inbound" 195 | access = "Allow" 196 | protocol = "Tcp" 197 | source_port_range = "*" 198 | destination_port_range = "8443" 199 | source_address_prefix = "*" 200 | destination_address_prefix = "*" 201 | } 202 | 203 | tags { 204 | Name = "${var.environment}-bigip-sg" 205 | environment = "${var.environment}" 206 | owner = "${var.owner}" 207 | group = "${var.group}" 208 | costcenter = "${var.costcenter}" 209 | application = "${var.application}" 210 | } 211 | } 212 | 213 | # Create the first network interface card for Management 214 | resource "azurerm_network_interface" "vm01-mgmt-nic" { 215 | name = "${var.prefix}-vm01-mgmt-nic" 216 | location = "${azurerm_resource_group.main.location}" 217 | resource_group_name = "${azurerm_resource_group.main.name}" 218 | network_security_group_id = "${azurerm_network_security_group.main.id}" 219 | 220 | ip_configuration { 221 | name = "primary" 222 | subnet_id = "${azurerm_subnet.Mgmt.id}" 223 | private_ip_address_allocation = "Static" 224 | private_ip_address = "${var.f5vm01mgmt}" 225 | public_ip_address_id = "${azurerm_public_ip.vm01mgmtpip.id}" 226 | } 227 | 228 | tags { 229 | Name = "${var.environment}-vm01-mgmt-int" 230 | environment = "${var.environment}" 231 | owner = "${var.owner}" 232 | group = "${var.group}" 233 | costcenter = "${var.costcenter}" 234 | application = "${var.application}" 235 | } 236 | } 237 | 238 | resource "azurerm_network_interface" "vm02-mgmt-nic" { 239 | name = "${var.prefix}-vm02-mgmt-nic" 240 | location = "${azurerm_resource_group.main.location}" 241 | resource_group_name = "${azurerm_resource_group.main.name}" 242 | network_security_group_id = "${azurerm_network_security_group.main.id}" 243 | 244 | ip_configuration { 245 | name = "primary" 246 | subnet_id = "${azurerm_subnet.Mgmt.id}" 247 | private_ip_address_allocation = "Static" 248 | private_ip_address = "${var.f5vm02mgmt}" 249 | public_ip_address_id = "${azurerm_public_ip.vm02mgmtpip.id}" 250 | } 251 | 252 | tags { 253 | Name = "${var.environment}-vm02-mgmt-int" 254 | environment = "${var.environment}" 255 | owner = "${var.owner}" 256 | group = "${var.group}" 257 | costcenter = "${var.costcenter}" 258 | application = "${var.application}" 259 | } 260 | } 261 | 262 | # Create the second network interface card for External 263 | resource "azurerm_network_interface" "vm01-ext-nic" { 264 | name = "${var.prefix}-vm01-ext-nic" 265 | location = "${azurerm_resource_group.main.location}" 266 | resource_group_name = "${azurerm_resource_group.main.name}" 267 | network_security_group_id = "${azurerm_network_security_group.main.id}" 268 | depends_on = ["azurerm_lb_backend_address_pool.backend_pool"] 269 | 270 | ip_configuration { 271 | name = "primary" 272 | subnet_id = "${azurerm_subnet.External.id}" 273 | private_ip_address_allocation = "Static" 274 | private_ip_address = "${var.f5vm01ext}" 275 | primary = true 276 | } 277 | 278 | ip_configuration { 279 | name = "secondary" 280 | subnet_id = "${azurerm_subnet.External.id}" 281 | private_ip_address_allocation = "Static" 282 | private_ip_address = "${var.f5vm01ext_sec}" 283 | } 284 | 285 | tags { 286 | Name = "${var.environment}-vm01-ext-int" 287 | environment = "${var.environment}" 288 | owner = "${var.owner}" 289 | group = "${var.group}" 290 | costcenter = "${var.costcenter}" 291 | application = "${var.application}" 292 | } 293 | } 294 | 295 | resource "azurerm_network_interface" "vm02-ext-nic" { 296 | name = "${var.prefix}-vm02-ext-nic" 297 | location = "${azurerm_resource_group.main.location}" 298 | resource_group_name = "${azurerm_resource_group.main.name}" 299 | network_security_group_id = "${azurerm_network_security_group.main.id}" 300 | depends_on = ["azurerm_lb_backend_address_pool.backend_pool"] 301 | 302 | ip_configuration { 303 | name = "primary" 304 | subnet_id = "${azurerm_subnet.External.id}" 305 | private_ip_address_allocation = "Static" 306 | private_ip_address = "${var.f5vm02ext}" 307 | primary = true 308 | } 309 | 310 | ip_configuration { 311 | name = "secondary" 312 | subnet_id = "${azurerm_subnet.External.id}" 313 | private_ip_address_allocation = "Static" 314 | private_ip_address = "${var.f5vm02ext_sec}" 315 | } 316 | 317 | tags { 318 | Name = "${var.environment}-vm01-ext-int" 319 | environment = "${var.environment}" 320 | owner = "${var.owner}" 321 | group = "${var.group}" 322 | costcenter = "${var.costcenter}" 323 | application = "${var.application}" 324 | } 325 | } 326 | 327 | resource "azurerm_network_interface" "backend01-ext-nic" { 328 | name = "${var.prefix}-backend01-ext-nic" 329 | location = "${azurerm_resource_group.main.location}" 330 | resource_group_name = "${azurerm_resource_group.main.name}" 331 | network_security_group_id = "${azurerm_network_security_group.main.id}" 332 | 333 | ip_configuration { 334 | name = "primary" 335 | subnet_id = "${azurerm_subnet.External.id}" 336 | private_ip_address_allocation = "Static" 337 | private_ip_address = "${var.backend01ext}" 338 | primary = true 339 | } 340 | 341 | tags { 342 | Name = "${var.environment}-backend01-ext-int" 343 | environment = "${var.environment}" 344 | owner = "${var.owner}" 345 | group = "${var.group}" 346 | costcenter = "${var.costcenter}" 347 | application = "app1" 348 | } 349 | } 350 | 351 | # Associate the Network Interface to the BackendPool 352 | resource "azurerm_network_interface_backend_address_pool_association" "bpool_assc_vm01" { 353 | depends_on = ["azurerm_lb_backend_address_pool.backend_pool", "azurerm_network_interface.vm01-ext-nic"] 354 | network_interface_id = "${azurerm_network_interface.vm01-ext-nic.id}" 355 | ip_configuration_name = "secondary" 356 | backend_address_pool_id = "${azurerm_lb_backend_address_pool.backend_pool.id}" 357 | } 358 | 359 | resource "azurerm_network_interface_backend_address_pool_association" "bpool_assc_vm02" { 360 | depends_on = ["azurerm_lb_backend_address_pool.backend_pool", "azurerm_network_interface.vm02-ext-nic"] 361 | network_interface_id = "${azurerm_network_interface.vm02-ext-nic.id}" 362 | ip_configuration_name = "secondary" 363 | backend_address_pool_id = "${azurerm_lb_backend_address_pool.backend_pool.id}" 364 | } 365 | 366 | # Setup Onboarding scripts 367 | data "template_file" "vm_onboard" { 368 | template = "${file("${path.module}/onboard.tpl")}" 369 | 370 | vars { 371 | uname = "${var.uname}" 372 | upassword = "${var.upassword}" 373 | DO_onboard_URL = "${var.DO_onboard_URL}" 374 | AS3_URL = "${var.AS3_URL}" 375 | libs_dir = "${var.libs_dir}" 376 | onboard_log = "${var.onboard_log}" 377 | } 378 | } 379 | 380 | data "template_file" "vm01_do_json" { 381 | template = "${file("${path.module}/cluster.json")}" 382 | 383 | vars { 384 | #Uncomment the following line for BYOL 385 | #local_sku = "${var.license1}" 386 | 387 | host1 = "${var.host1_name}" 388 | host2 = "${var.host2_name}" 389 | local_host = "${var.host1_name}" 390 | local_selfip = "${var.f5vm01ext}" 391 | remote_host = "${var.host2_name}" 392 | remote_selfip = "${var.f5vm02ext}" 393 | gateway = "${local.ext_gw}" 394 | dns_server = "${var.dns_server}" 395 | ntp_server = "${var.ntp_server}" 396 | timezone = "${var.timezone}" 397 | admin_user = "${var.uname}" 398 | admin_password = "${var.upassword}" 399 | } 400 | } 401 | 402 | data "template_file" "vm02_do_json" { 403 | template = "${file("${path.module}/cluster.json")}" 404 | 405 | vars { 406 | #Uncomment the following line for BYOL 407 | #local_sku = "${var.license2}" 408 | 409 | host1 = "${var.host1_name}" 410 | host2 = "${var.host2_name}" 411 | local_host = "${var.host2_name}" 412 | local_selfip = "${var.f5vm02ext}" 413 | remote_host = "${var.host1_name}" 414 | remote_selfip = "${var.f5vm01ext}" 415 | gateway = "${local.ext_gw}" 416 | dns_server = "${var.dns_server}" 417 | ntp_server = "${var.ntp_server}" 418 | timezone = "${var.timezone}" 419 | admin_user = "${var.uname}" 420 | admin_password = "${var.upassword}" 421 | } 422 | } 423 | 424 | data "template_file" "as3_json" { 425 | template = "${file("${path.module}/as3.json")}" 426 | 427 | vars { 428 | rg_name = "${azurerm_resource_group.main.name}" 429 | subscription_id = "${var.SP["subscription_id"]}" 430 | tenant_id = "${var.SP["tenant_id"]}" 431 | client_id = "${var.SP["client_id"]}" 432 | client_secret = "${var.SP["client_secret"]}" 433 | } 434 | } 435 | 436 | # Create F5 BIGIP VMs 437 | resource "azurerm_virtual_machine" "f5vm01" { 438 | name = "${var.prefix}-f5vm01" 439 | location = "${azurerm_resource_group.main.location}" 440 | resource_group_name = "${azurerm_resource_group.main.name}" 441 | primary_network_interface_id = "${azurerm_network_interface.vm01-mgmt-nic.id}" 442 | network_interface_ids = ["${azurerm_network_interface.vm01-mgmt-nic.id}", "${azurerm_network_interface.vm01-ext-nic.id}"] 443 | vm_size = "${var.instance_type}" 444 | availability_set_id = "${azurerm_availability_set.avset.id}" 445 | 446 | # Uncomment this line to delete the OS disk automatically when deleting the VM 447 | delete_os_disk_on_termination = true 448 | 449 | 450 | # Uncomment this line to delete the data disks automatically when deleting the VM 451 | delete_data_disks_on_termination = true 452 | 453 | storage_image_reference { 454 | publisher = "f5-networks" 455 | offer = "${var.product}" 456 | sku = "${var.image_name}" 457 | version = "${var.bigip_version}" 458 | } 459 | 460 | storage_os_disk { 461 | name = "${var.prefix}vm01-osdisk" 462 | caching = "ReadWrite" 463 | create_option = "FromImage" 464 | managed_disk_type = "Standard_LRS" 465 | } 466 | 467 | os_profile { 468 | computer_name = "${var.prefix}vm01" 469 | admin_username = "${var.uname}" 470 | admin_password = "${var.upassword}" 471 | custom_data = "${data.template_file.vm_onboard.rendered}" 472 | } 473 | 474 | os_profile_linux_config { 475 | disable_password_authentication = false 476 | } 477 | 478 | plan { 479 | name = "${var.image_name}" 480 | publisher = "f5-networks" 481 | product = "${var.product}" 482 | } 483 | 484 | tags { 485 | Name = "${var.environment}-f5vm01" 486 | environment = "${var.environment}" 487 | owner = "${var.owner}" 488 | group = "${var.group}" 489 | costcenter = "${var.costcenter}" 490 | application = "${var.application}" 491 | } 492 | } 493 | 494 | resource "azurerm_virtual_machine" "f5vm02" { 495 | name = "${var.prefix}-f5vm02" 496 | location = "${azurerm_resource_group.main.location}" 497 | resource_group_name = "${azurerm_resource_group.main.name}" 498 | primary_network_interface_id = "${azurerm_network_interface.vm02-mgmt-nic.id}" 499 | network_interface_ids = ["${azurerm_network_interface.vm02-mgmt-nic.id}", "${azurerm_network_interface.vm02-ext-nic.id}"] 500 | vm_size = "${var.instance_type}" 501 | availability_set_id = "${azurerm_availability_set.avset.id}" 502 | 503 | # Uncomment this line to delete the OS disk automatically when deleting the VM 504 | delete_os_disk_on_termination = true 505 | 506 | 507 | # Uncomment this line to delete the data disks automatically when deleting the VM 508 | delete_data_disks_on_termination = true 509 | 510 | storage_image_reference { 511 | publisher = "f5-networks" 512 | offer = "${var.product}" 513 | sku = "${var.image_name}" 514 | version = "${var.bigip_version}" 515 | } 516 | 517 | storage_os_disk { 518 | name = "${var.prefix}vm02-osdisk" 519 | caching = "ReadWrite" 520 | create_option = "FromImage" 521 | managed_disk_type = "Standard_LRS" 522 | } 523 | 524 | os_profile { 525 | computer_name = "${var.prefix}vm02" 526 | admin_username = "${var.uname}" 527 | admin_password = "${var.upassword}" 528 | custom_data = "${data.template_file.vm_onboard.rendered}" 529 | } 530 | 531 | os_profile_linux_config { 532 | disable_password_authentication = false 533 | } 534 | 535 | plan { 536 | name = "${var.image_name}" 537 | publisher = "f5-networks" 538 | product = "${var.product}" 539 | } 540 | 541 | tags { 542 | Name = "${var.environment}-f5vm02" 543 | environment = "${var.environment}" 544 | owner = "${var.owner}" 545 | group = "${var.group}" 546 | costcenter = "${var.costcenter}" 547 | application = "${var.application}" 548 | } 549 | } 550 | 551 | # backend VM 552 | resource "azurerm_virtual_machine" "backendvm" { 553 | name = "backendvm" 554 | location = "${azurerm_resource_group.main.location}" 555 | resource_group_name = "${azurerm_resource_group.main.name}" 556 | 557 | network_interface_ids = ["${azurerm_network_interface.backend01-ext-nic.id}"] 558 | vm_size = "Standard_DS1_v2" 559 | 560 | storage_os_disk { 561 | name = "backendOsDisk" 562 | caching = "ReadWrite" 563 | create_option = "FromImage" 564 | managed_disk_type = "Premium_LRS" 565 | } 566 | 567 | storage_image_reference { 568 | publisher = "Canonical" 569 | offer = "UbuntuServer" 570 | sku = "16.04.0-LTS" 571 | version = "latest" 572 | } 573 | 574 | os_profile { 575 | computer_name = "backend01" 576 | admin_username = "azureuser" 577 | admin_password = "${var.upassword}" 578 | custom_data = <<-EOF 579 | #!/bin/bash 580 | apt-get update -y 581 | apt-get install -y docker.io 582 | docker run -d -p 80:80 --net=host --restart unless-stopped -e F5DEMO_APP=website -e F5DEMO_NODENAME='F5 Azure' -e F5DEMO_COLOR=ffd734 -e F5DEMO_NODENAME_SSL='F5 Azure (SSL)' -e F5DEMO_COLOR_SSL=a0bf37 chen23/f5-demo-app:ssl 583 | EOF 584 | } 585 | 586 | os_profile_linux_config { 587 | disable_password_authentication = false 588 | } 589 | 590 | tags { 591 | Name = "${var.environment}-backend01" 592 | environment = "${var.environment}" 593 | owner = "${var.owner}" 594 | group = "${var.group}" 595 | costcenter = "${var.costcenter}" 596 | application = "${var.application}" 597 | } 598 | } 599 | 600 | 601 | # Run Startup Script 602 | resource "azurerm_virtual_machine_extension" "f5vm01-run-startup-cmd" { 603 | name = "${var.environment}-f5vm01-run-startup-cmd" 604 | depends_on = ["azurerm_virtual_machine.f5vm01", "azurerm_virtual_machine.backendvm"] 605 | location = "${var.region}" 606 | resource_group_name = "${azurerm_resource_group.main.name}" 607 | virtual_machine_name = "${azurerm_virtual_machine.f5vm01.name}" 608 | publisher = "Microsoft.OSTCExtensions" 609 | type = "CustomScriptForLinux" 610 | type_handler_version = "1.2" 611 | # publisher = "Microsoft.Azure.Extensions" 612 | # type = "CustomScript" 613 | # type_handler_version = "2.0" 614 | 615 | settings = <>$LOG_FILE 11 | else 12 | #if file exists, exit as only want to run once 13 | exit 14 | fi 15 | 16 | exec 1>$LOG_FILE 2>&1 17 | 18 | # CHECK TO SEE NETWORK IS READY 19 | CNT=0 20 | while true 21 | do 22 | STATUS=$(curl -s -k -I example.com | grep HTTP) 23 | if [[ $STATUS == *"200"* ]]; then 24 | echo "Got 200! VE is Ready!" 25 | break 26 | elif [ $CNT -le 6 ]; then 27 | echo "Status code: $STATUS Not done yet..." 28 | CNT=$[$CNT+1] 29 | else 30 | echo "GIVE UP..." 31 | break 32 | fi 33 | sleep 10 34 | done 35 | 36 | ### DOWNLOAD ONBOARDING PKGS 37 | # Could be pre-packaged or hosted internally 38 | 39 | admin_username='${uname}' 40 | admin_password='${upassword}' 41 | CREDS="admin:"$admin_password 42 | DO_URL='${DO_onboard_URL}' 43 | DO_FN=$(basename "$DO_URL") 44 | AS3_URL='${AS3_URL}' 45 | AS3_FN=$(basename "$AS3_URL") 46 | 47 | mkdir -p ${libs_dir} 48 | 49 | echo -e "\n"$(date) "Download Declarative Onboarding Pkg" 50 | curl -L -o ${libs_dir}/$DO_FN $DO_URL 51 | 52 | echo -e "\n"$(date) "Download AS3 Pkg" 53 | curl -L -o ${libs_dir}/$AS3_FN $AS3_URL 54 | sleep 20 55 | 56 | # Copy the RPM Pkg to the file location 57 | cp ${libs_dir}/*.rpm /var/config/rest/downloads/ 58 | 59 | # Install Declarative Onboarding Pkg 60 | DATA="{\"operation\":\"INSTALL\",\"packageFilePath\":\"/var/config/rest/downloads/$DO_FN\"}" 61 | echo -e "\n"$(date) "Install DO Pkg" 62 | curl -u $CREDS -X POST http://localhost:8100/mgmt/shared/iapp/package-management-tasks -d $DATA 63 | 64 | # Install AS3 Pkg 65 | DATA="{\"operation\":\"INSTALL\",\"packageFilePath\":\"/var/config/rest/downloads/$AS3_FN\"}" 66 | echo -e "\n"$(date) "Install AS3 Pkg" 67 | curl -u $CREDS -X POST http://localhost:8100/mgmt/shared/iapp/package-management-tasks -d $DATA 68 | 69 | # Check DO Ready 70 | CNT=0 71 | while true 72 | do 73 | STATUS=$(curl -u $CREDS -X GET -s -k -I https://localhost/mgmt/shared/declarative-onboarding | grep HTTP) 74 | if [[ $STATUS == *"200"* ]]; then 75 | echo "Got 200! Declarative Onboarding is Ready!" 76 | break 77 | elif [ $CNT -le 6 ]; then 78 | echo "Status code: $STATUS DO Not done yet..." 79 | CNT=$[$CNT+1] 80 | else 81 | echo "GIVE UP..." 82 | break 83 | fi 84 | sleep 10 85 | done 86 | 87 | # Check AS3 Ready 88 | CNT=0 89 | while true 90 | do 91 | STATUS=$(curl -u $CREDS -X GET -s -k -I https://localhost/mgmt/shared/appsvcs/info | grep HTTP) 92 | if [[ $STATUS == *"200"* ]]; then 93 | echo "Got 200! AS3 is Ready!" 94 | break 95 | elif [ $CNT -le 6 ]; then 96 | echo "Status code: $STATUS AS3 Not done yet..." 97 | CNT=$[$CNT+1] 98 | else 99 | echo "GIVE UP..." 100 | break 101 | fi 102 | sleep 10 103 | done 104 | 105 | 106 | -------------------------------------------------------------------------------- /HA_via_lb_DO_AS3/provider.tf: -------------------------------------------------------------------------------- 1 | # Configure the Microsoft Azure Provider, replace Service Principal and Subscription with your own 2 | provider "azurerm" { 3 | subscription_id = "${var.SP["subscription_id"]}" 4 | client_id = "${var.SP["client_id"]}" 5 | client_secret = "${var.SP["client_secret"]}" 6 | tenant_id = "${var.SP["tenant_id"]}" 7 | } 8 | 9 | -------------------------------------------------------------------------------- /HA_via_lb_DO_AS3/variables.tf: -------------------------------------------------------------------------------- 1 | # REST API Setting 2 | variable rest_do_uri { default = "/mgmt/shared/declarative-onboarding" } 3 | variable rest_as3_uri { default = "/mgmt/shared/appsvcs/declare" } 4 | variable rest_do_method { default = "POST" } 5 | variable rest_as3_method { default = "POST" } 6 | variable rest_vm01_do_file {default = "vm01_do_data.json" } 7 | variable rest_vm02_do_file {default = "vm02_do_data.json" } 8 | variable rest_vm_as3_file {default = "vm_as3_data.json" } 9 | 10 | # Azure Environment 11 | variable "SP" { 12 | type = "map" 13 | default = { 14 | subscription_id = "xxxxx" 15 | client_id = "xxxxx" 16 | client_secret = "xxxxx" 17 | tenant_id = "xxxxx" 18 | } 19 | } 20 | variable prefix { default = "zludemo" } 21 | variable uname { default = "azureuser" } 22 | variable upassword { default = "Default12345" } 23 | variable location { default = "eastus" } 24 | variable region { default = "East US" } 25 | 26 | # NETWORK 27 | variable cidr { default = "10.90.0.0/16" } 28 | variable "subnets" { 29 | type = "map" 30 | default = { 31 | "subnet1" = "10.90.1.0/24" 32 | "subnet2" = "10.90.2.0/24" 33 | "subnet3" = "10.90.3.0/24" 34 | } 35 | } 36 | variable f5vm01mgmt { default = "10.90.1.4" } 37 | variable f5vm01ext { default = "10.90.2.4" } 38 | variable f5vm01ext_sec { default = "10.90.2.11" } 39 | variable f5vm02mgmt { default = "10.90.1.5" } 40 | variable f5vm02ext { default = "10.90.2.5" } 41 | variable f5vm02ext_sec { default = "10.90.2.12" } 42 | variable backend01ext { default = "10.90.2.101" } 43 | 44 | # BIGIP Image 45 | variable instance_type { default = "Standard_DS4_v2" } 46 | variable image_name { default = "f5-bigip-virtual-edition-25m-best-hourly" } 47 | variable product { default = "f5-big-ip-best" } 48 | variable bigip_version { default = "latest" } 49 | 50 | # BIGIP Setup 51 | variable license1 { default = ""} 52 | variable license2 { default = ""} 53 | variable host1_name { default = "f5vm01"} 54 | variable host2_name { default = "f5vm02"} 55 | variable dns_server { default = "8.8.8.8" } 56 | variable ntp_server { default = "0.us.pool.ntp.org" } 57 | variable timezone { default = "UTC" } 58 | ## Please check and update the latest DO URL from https://github.com/F5Networks/f5-declarative-onboarding/releases 59 | variable DO_onboard_URL { default = "https://github.com/garyluf5/f5tools/raw/master/f5-declarative-onboarding-1.3.0-4.noarch.rpm" } 60 | ## Please check and update the latest AS3 URL from https://github.com/F5Networks/f5-appsvcs-extension/releases/latest 61 | variable AS3_URL { default = "https://github.com/garyluf5/f5tools/raw/master/f5-appsvcs-3.9.0-3.noarch.rpm" } 62 | variable libs_dir { default = "/config/cloud/azure/node_modules" } 63 | variable onboard_log { default = "/var/log/startup-script.log" } 64 | 65 | # TAGS 66 | variable purpose { default = "public" } 67 | variable environment { default = "f5env" } #ex. dev/staging/prod 68 | variable owner { default = "f5owner" } 69 | variable group { default = "f5group" } 70 | variable costcenter { default = "f5costcenter" } 71 | variable application { default = "f5app" } 72 | 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # f5_terraform 2 | 3 | * HA_via_lb_DO_AS3 - This Terraform template uses the Azurerm provider to build out all the necessary Azure objects and then use F5 Declarative Onboarding and AS3 REST ochistration tool for initial onboarding and configuration 4 | 5 | --------------------------------------------------------------------------------