automation
424 TopicsMicrosoft 365 IP Steering python script
Hello! Hola! I have created a small and rudimentary script that generates a datagroup with MS 365 IPv4 and v6 addresses to be used by an iRule or policy. There are other scripts that solve this same issue but either they were: based on iRulesLX, which forces you to enable iRuleLX only for this, and made me run into issues when upgrading (memory table got filled with nonsense) based on the XML version of the list, which MS changed to a JSON file. This script is a super simple bash script that calls another super simple python file, and a couple of helper files. The biggest To Do are: Add a more secure approach to password usage. Right now, it is stored in a parameters file locked away with permissions. There should be a better way. Add support for URLs. You can find the contents here:https://github.com/teoiovine-novared/fetch-office365/tree/main I appreciate advice, (constructive) criticism and questions all the same! Thank you for your time.105Views1like3CommentsMicrosoft 365 IP Steering python Script
Hello! Hola! I have created a small and rudimentary script that generates a datagroup with MS 365 IPv4 and v6 addresses to be used by an iRule or policy. There are other scripts that solve this same issue but either they were: based on iRulesLX which forces you to enable iRuleLX only for this, and made me run into issues when upgrading (memory table got filled with nonsense) based on the XML version of the list which MS changed to a JSON file. This script is a super simple bash script that calls another super simple python file, and a couple of helper files. The biggest To Do are: Add a more secure approach to password usage. Right now, it is stored in a parameters file locked away with permissions. There should be a better way. Add support for URLs. You can find the contents here:https://github.com/teoiovine-novared/fetch-office365/tree/main I appreciate advice, (constructive) criticism and questions all the same! Thank you for your time.18Views0likes0CommentsBIG-IP Next – Introduction to the Blueprints API
If you have ever attempted to automate the BIG-IP configuration, you are probably familiar with F5’s AS3 extension. Although AS3 is supported in BIG-IP Next, there is another API that might be the better option if you haven’t started your migration journey up until now. This is called the Blueprints API. In this article, I want to show you how to use it to automate your applications with AS3. Overview When you use the BIG-IP Next GUI, you instantly see the benefits of having a centrally managed configuration across all your BIG-IP instances. The steps to create an application service in the GUI now have a siloed setup where you define 4 main sections separately: Application Properties Virtual Server Properties Pool Properties Deployment Properties Each one of these sections allows you to adjust areas of your application service while still having a way to manage configurations across multiple BIG-IP instances. In other words, you can define one pool under the pool properties, but still have different pool members under the deployment properties for each of your BIG-IP instances. This creates a centrally managed application service that does not require the exact same configuration in each environment. When you perform these tasks in the GUI, BIG-IP Next is generating its own API calls internally. It takes each of your configuration items outlined in the 4 sections above and defines the application service as a Blueprint. This Blueprint is then used to modify anything about the configuration/deployment moving forward. If you aren’t a fan of using a GUI and you are trying to automate, this same exact API is exposed to you as well. This means we get to use the same centrally managed configuration in our API calls. It also means that we can easily automate existing application services by simply using the API to manage them moving forward. So what does this Blueprint API look like? Below is sample JSON used to create a Blueprint called “bobs-blueprint”: { "name":"bobs-blueprint", "set_name": "Examples", "template_name": "http", "parameters": { "application_description": "", "application_name": "bobs-blueprint", "enable_Global_Resiliency": false, "pools": [ { "loadBalancingMode": "round-robin", "monitorType": [ "http" ], "poolName": "juice", "servicePort": 8080 } ], "virtuals": [ { "FastL4_TOS": 0, "FastL4_idleTimeout": 600, "FastL4_looseClose": true, "FastL4_looseInitialization": true, "FastL4_pvaAcceleration": "full", "FastL4_pvaDynamicClientPackets": 1, "FastL4_pvaDynamicServerPackets": 0, "FastL4_resetOnTimeout": true, "FastL4_tcpCloseTimeout": 43200, "FastL4_tcpHandshakeTimeout": 43200, "InspectionServicesEnum": [], "TCP_idle_timeout": 60, "UDP_idle_timeout": 60, "ciphers": "DEFAULT", "ciphers_server": "DEFAULT", "enable_Access": false, "enable_FastL4": false, "enable_FastL4_DSR": false, "enable_HTTP2_Profile": false, "enable_HTTP_Profile": false, "enable_InspectionServices": false, "enable_SsloPolicy": false, "enable_TCP_Profile": false, "enable_TLS_Client": false, "enable_TLS_Server": false, "enable_UDP_Profile": false, "enable_WAF": false, "enable_iRules": false, "enable_mirroring": true, "enable_snat": true, "iRulesEnum": [], "multiCertificatesEnum": [], "perRequestAccessPolicyEnum": "", "pool": "juice", "snat_addresses": [], "snat_automap": true, "tls_c_1_1": false, "tls_c_1_2": true, "tls_c_1_3": false, "tls_s_1_2": true, "tls_s_1_3": false, "trustCACertificate": "", "virtualName": "bobs-vs", "virtualPort": 80 } ] } } As you can see, the structure of this JSON is siloed in a very similar way to the GUI: Note: For those readers who are wondering where the Deployment section is, that is handled in a separate API call after the blueprint has been created. I’ll discuss that in more detail later. In the sections below, I’ll review a few of the API endpoints you can use with some steps on how to perform the following common tasks: Viewing an existing Blueprint Creating a new Blueprint Deploying a Blueprint Viewing an Existing Blueprint Before we start creating a new Blueprint from scratch, it is probably a good idea to explain how we can view a list of our current Blueprints. To do so, we simply make a GET request to the following API endpoint: GET https://{{bigip_next_cm_mgmt_ip}}/api/v1/spaces/default/appsvcs/blueprints This will return a list of every Blueprint created by the GUI and/or API. Below is an example output: { "_embedded": { "appsvcs": [ { "_links": { "self": { "href": "/api/v1/spaces/default/appsvcs/blueprints//3f2ef264-cf09-45c8-a925-f2c8fccf09f6" } }, "created": "2024-06-25T13:32:22.160399Z", "deployments": [ { "id": "1e5f9c06-8800-4ab7-ad5e-648d55b83b68", "instance_id": "ce179e66-b075-4068-bc4e-8e212954da49", "target": { "address": "10.2.1.3" }, "parameters": { "pools": [ { "isServicePool": false, "poolMembers": [ { "address": "10.1.3.100", "name": "old" }, { "address": "10.2.3.100", "name": "new" } ], "poolName": "juice" } ], "virtuals": [ { "allow_networks": [], "enable_allow_networks": false, "virtualAddress": "10.2.2.11", "virtualName": "juice-shop" } ] }, "last_successful_deploy_time": "2024-06-25T17:46:00.193649Z", "modified": "2024-06-25T17:46:00.193649Z", "last_record": { "id": "cb6a06a1-c66d-41c3-a747-9a27b101a0f1", "task_id": "6a65642d-810b-4194-9693-91a15f6d1ef0", "created_application_path": "/applications/tenantSrLEVevFQnWwXT90590F3USQ/juice-shop", "start_time": "2024-06-25T17:45:55.392732Z", "end_time": "2024-06-25T17:46:00.193649Z", "status": "completed" } }, { "id": "001e14e8-7900-482a-bdd4-aca35967a5cc", "instance_id": "0546acf5-3b88-422d-a948-28bbf0973212", "target": { "address": "10.2.1.4" }, "parameters": { "pools": [ { "isServicePool": false, "poolMembers": [ { "address": "10.1.3.100", "name": "old" }, { "address": "10.2.3.100", "name": "new" } ], "poolName": "juice" } ], "virtuals": [ { "allow_networks": [], "enable_allow_networks": false, "virtualAddress": "10.2.2.12", "virtualName": "juice-shop" } ] }, "last_successful_deploy_time": "2024-06-25T17:46:07.94836Z", "modified": "2024-06-25T17:46:07.94836Z", "last_record": { "id": "8a8a29be-e56b-4ef1-bf6a-92f7ccc9e9b7", "task_id": "0632cc18-9f0f-4a5e-875a-0d769b02e19b", "created_application_path": "/applications/tenantSrLEVevFQnWwXT90590F3USQ/juice-shop", "start_time": "2024-06-25T17:45:55.406377Z", "end_time": "2024-06-25T17:46:07.94836Z", "status": "completed" } } ], "deployments_count": { "total": 2, "completed": 2 }, "description": "", "fqdn": "", "gslb_enabled": false, "id": "3f2ef264-cf09-45c8-a925-f2c8fccf09f6", "modified": "2024-06-25T17:32:09.174243Z", "name": "juice-shop", "set_name": "Examples", "successful_instances": 2, "template_name": "http", "tenant_name": "tenantSrLEVevFQnWwXT90590F3USQ", "type": "FAST" } ] }, "_links": { "self": { "href": "/api/v1/spaces/default/appsvcs/blueprints/" } }, "count": 1, "total": 1 } In the example above, I only have one Blueprint in my BIG-IP Next CM instance. If we look deeper into the output, we can start to see some detail around the configuration parameters as well as the deployment parameters for each BIG-IP. There is also an ID field in the JSON that we can use to reference a specific Blueprint. In the example above, we have: "id": "3f2ef264-cf09-45c8-a925-f2c8fccf09f6" This is important because as we start to modify, deploy, or delete our existing blueprints, we will need this ID to be able to make changes. We can also use this ID to view more detail on a specific Blueprint rather than an entire list of all Blueprints. To do so, we simply follow make a request to the endpoint below: GET https://{{bigip_next_cm_mgmt_ip}}/api/v1/spaces/default/appsvcs/blueprints/{{Blueprint_id}} In our example, this would be: GET https://{{bigip_next_cm_mgmt_ip}}/api/v1/spaces/default/appsvcs/blueprints/3f2ef264-cf09-45c8-a925-f2c8fccf09f6 The output from this API call provides robust detail on the Blueprint. It is probably too much detail to paste in an article like this, but there are some examples here if interested: https://clouddocs.f5.com/products/bigip-next/mgmt-api/latest/ApiReferences/bigip_public_api_ref/r_openapi-next.html#tag/Application-Services/operation/GetApplicationByID Viewing a Blueprint like this can provide us with the latest configuration of our application service so that we can ensure we are using the most up-to-date files. It also can provide us with some templates/example configurations that we can use to create new application services moving forward. Creating a new Blueprint Now that we have a pretty good understanding of the JSON structure and we know how to view some examples of Blueprints that have already been created, we can simply use them as a reference and create our own Blueprint from scratch. The basic format for creating a new Blueprint is below: { "name": <blueprint_name>, "set_name": <template_set> "template_name": <template_name>, "parameters": { "application_description": <simple_description>, "application_name": <blueprint_name>, "enable_Global_Resiliency": false, "pools": [ { <pool_configuration_parameters> } ], "virtuals": [ { <virtual_server_configuration parameters> } ] } } More detail on each of the variable values below: <blueprint_name> - This is the name you choose for your blueprint. I generally recommend this name be the same in both the “name” field and the “application_name” field which is why in the JSON above you’ll see this in both. <template_set> - This is going to be the template set containing your FAST template. If you are using the default templates provided to you, this value would be “Examples” <template_name> - This is the specific FAST template you are going to use for the configuration. If you are using the default template provided to you, this value would be “http” <simple_description> - This can be any short description you would like to use for your application service. <pool_configuration_parameters> - This will be the list of parameters that you are going to define for your pool. You do not have to fill in every single value if the FAST template contains values for that field. <virtual_server_configuration parameters> - This will be the list of parameters that you are going to define for your virtual server. You do not have to fill in every single value if the FAST template contains values for that field. Important Note: When creating your JSON, you will be defining a FAST template to use along with your application service (just like you would in the GUI). This means that you do not have to fill out every value under your pool and virtual server configuration. It will take in the values provided from your FAST template. With our guide above, we can now make a new Blueprint for the “bobs-blueprint” example I referenced earlier: { "name":"bobs-blueprint", "set_name": "Examples", "template_name": "http", "parameters": { "application_description":"This is a test of the blueprints api", "application_name": "bobs-blueprint", "pools": [ { "loadBalancingMode": "round-robin", "monitorType": [ "http" ], "poolName": "juice_pool", "servicePort": 3000 } ], "virtuals": [ { "pool": "juice_pool", "virtualName": "blueprint_vs", "virtualPort": 80 } ] } } As you can see, this is a much more condensed version of the original JSON I had for the example shown in the beginning of this article. Again, this is because we are referencing the FAST template “Examples/http” and taking in those values to configure the rest of the application service. With our newly created JSON, the last step to creating this Blueprint is to send this in a POST request to the following API endpoint: POST https://{{bigip_next_cm_mgmt_ip}}/api/v1/spaces/default/appsvcs/blueprints After sending our POST, you'll notice we are given the "id" of the Blueprint in the response. As mentioned above, we can use this ID to modify, deploy, etc. { "_links": { "self": { "href": "/api/v1/spaces/default/appsvcs/blueprints/9c35a614-65ac-4d18-8082-589ea9bc78d9/deployments" } }, "deployments": [ { "deploymentID": "1a153f44-acaf-4487-81c7-61b8b5498627", "instanceID": "4ef739d1-9ef1-4eb7-a5bb-36c6d1334b16", "status": "pending", "taskID": "518534c8-9368-48dd-b399-94f55e72d5a7", "task_type": "CREATE" }, { "deploymentID": "82ca8d6d-dbfd-43a8-a604-43f170d9f190", "instanceID": "0546acf5-3b88-422d-a948-28bbf0973212", "status": "pending", "taskID": "7ea24157-1412-4963-9560-56fb0ab78d8c", "task_type": "CREATE" } ], "id": "9c35a614-65ac-4d18-8082-589ea9bc78d9" } Now that the Blueprint has been created, we can go into our BIG-IP Next CM GUI and see our newly created application service: You’ll notice that our newly created application service is in Draft mode. This is because we have not deployed the service yet. We’ll discuss that in the next section. Deploying a Blueprint Once we have our Blueprint created, the final step is to configure the deployment. As discussed above, this is done through a separate API Call. The format for a deployment is as follows: { "deployments": [ { "parameters": { "pools": [ { "poolName": <pool_name> "poolMembers": [ { "name": <node1_name>, "address": <node1_ip_address> }, { "name": <node2_name>, "address": <node2_ip_address> } ] } ], "virtuals": [ { "virtualName": <virtual_server_name>, "virtualAddress": <virtual_server_ip_address> } ] }, "target": { "address": <bigip_instance_ip_address> }, "allow_overwrite": true } ] } Keep in mind that some of these values above are referencing names from your Blueprint configuration. These names need to be exactly the same. See below for more detail on each of these values: <pool_name> - This references the pool from your Blueprint. This value must match what was used for “poolName” in the pool configuration of the Blueprint. <node1_name> - This is any name you choose to describe your node in the pool <node1_ip_address> - This is the specific IP address for your node <node2_name> - If you are using more than one node, this would be the name you choose to represent your second node in the pool. This format can repeat for 3 nodes, 4 nodes, etc. <node2_ip_address> - If you are using more than one node, this would be the IP address of your second node. This format can repeat for 3 nodes, 4 nodes, etc. <virtual_server_name> - This references the virtual server from your Blueprint. This value must match what was used for “virtualName” in the virtuals configuration of the Blueprint. <virtual_server_ip_address> - This would be the IP address of the Virtual Server being deployed on the BIG-IP <bigip_instance_ip_address> - This is the IP address of the BIG-IP instance we are deploying to Important Note: If you are deploying the same application to more than one BIG-IP instance, you can include multiple deployment blocks in your API call. Using the format above, we can now create our deployment for “bobs-blueprint”: { "deployments": [ { "parameters": { "pools": [ { "poolName": "juice_pool", "poolMembers": [ { "name": "node1", "address": "10.1.3.100" } ] } ], "virtuals": [ { "virtualName": "blueprint_vs", "virtualAddress": "10.2.2.15" } ] }, "target": { "address": "10.2.1.3" }, "allow_overwrite": true }, { "parameters": { "pools": [ { "poolName": "juice_pool", "poolMembers": [ { "name": "node1", "address": "10.2.3.100" } ] } ], "virtuals": [ { "virtualName": "blueprint_vs", "virtualAddress": "10.2.2.20" } ] }, "target": { "address": "10.2.1.4" }, "allow_overwrite": true } ] } In this example deployment, I am deploying to two separate BIG-IP instances (10.2.1.3 and 10.2.1.4). This is where we can really start to see the value of the Blueprints API. With this structure, I can use the same pool and virtual server setup from our Blueprint, while still using different Virtual Server and Node IP addresses for the deployment at each instance. All of this is done with one API call. The final step is to send this in a POST request to our deployments endpoint. The endpoint is very similar to viewing a blueprint as it uses our same Blueprint ID. See the format below: POST https://{{bigip_next_cm_mgmt_ip}}/api/v1/spaces/default/appsvcs/blueprints/{{Blueprint_id}}/deployments Using the ID from the response we received after creating our example blueprint, our endpoint would be: POST https://{{bigip_next_cm_mgmt_ip}}/api/v1/spaces/default/appsvcs/blueprints/9c35a614-65ac-4d18-8082-589ea9bc78d9/deployments After sending our POST, we can go back to the BIG-IP Next CM GUI and see our application service is no longer considered a Draft. If we click into the application service, we’ll see our two deployments are up and healthy: Conclusion Hopefully after reading this article, you can see the value of using the Blueprints API for your automation. I think as an alternative to other automation methods, this can provide benefits such as: Same centrally managed format/structure as GUI created applications Since the BIG-IP Next CM GUI is already creating these JSON files under the hood, we can easily automate existing applications by using the Blueprints API for them moving forward Deployments are handled separately from your application configuration You can deploy your application service to multiple BIG-IP instances at once Combining the Blueprints API with FAST templates allows you make application on-boarding much more streamlined. If you liked this article and are looking for more information our our Blueprints API, please visit the API documentation here: https://clouddocs.f5.com/products/bigip-next/mgmt-api/latest/ApiReferences/bigip_public_api_ref/r_openapi-next.html#tag/Application-Services/operation/GetAllApplications233Views2likes2CommentsWhat is an iApp?
iApp is a seriously cool, game changing technology that was released in F5’s v11. There are so many benefits to our customers with this tool that I am going to break it down over a series of posts. Today we will focus on what it is. Hopefully you are already familiar with the power of F5’s iRules technology. If not, here is a quick background. F5 products support a scripting language based on TCL. This language allows an administrator to tell their BIG-IP to intercept, inspect, transform, direct and track inbound or outbound application traffic. An iRule is the bit of code that contains the set of instructions the system uses to process data flowing through it, either in the header or payload of a packet. This technology allows our customers to solve real-time application issues, security vulnerabilities, etc that are unique to their environment or are time sensitive. An iApp is like iRules, but for the management plane. Again, there is a scripting language that administrators can build instructions the system will use. But instead of describing how to process traffic, in the case of iApp, it is used to describe the user interface and how the system will act on information gathered from the user. The bit of code that contains these instructions is referred to as an iApp or iApp template. A system administrator can use F5-provided iApp templates installed on their BIG-IP to configure a service for a new application. They will be presented with the text and input fields defined by the iApp author. Once complete, their answers are submitted, and the template implements the configuration. First an application service object (ASO) is created that ties together all the configuration objects which are created, like virtual servers and profiles. Each object created by the iApp is then marked with the ASO to identify their membership in the application for future management and reporting. That about does it for what an iApp is…..next up, how they can work for you.1.3KViews0likes4CommentsIs anyone using Certbot for F5 certificate automation? If not, what tool do you use?
Currently, I'm having to manually update certs on our F5 and I'm wondering what other people are using to automate this. We use Sectigo which supports the Certbot F5 plugin, but a fellow tech that tested it said it doesn't work when a vserver has more than one SSL profile assigned. Is anyone using the Certbot tool? If not, what tool are you using? I like to be able to automate this (and be confident it "just works"). Thanks!Solved113Views0likes2CommentsVIPTest: Rapid Application Testing for F5 Environments
VIPTest is a Python-based tool for efficiently testing multiple URLs in F5 environments, allowing quick assessment of application behavior before and after configuration changes. It supports concurrent processing, handles various URL formats, and provides detailed reports on HTTP responses, TLS versions, and connectivity status, making it useful for migrations and routine maintenance.530Views5likes2CommentsNGINX Virtual Machine Building with cloud-init
Traditionally, building new servers was a manual process. A system administrator had a run book with all the steps required and would perform each task one by one. If the admin had multiple servers to build the same steps were repeated over and over. All public cloud compute platforms provide an automation tool called cloud-init that makes it easy to automate configuration tasks while a new VM instance is being launched. In this article, you will learn how to automate the process of building out a new NGINX Plus server usingcloud-init.469Views3likes4CommentsAutomate ASM "Ready to Be Enforced" Attack Signatures
Hi All, Problem scenario is this: Multiple F5 ASM deplyoments which use BigIQ to push out updated attack signatures ( works well ) and a 14 day Enforcement Readiness Period. This all works well up to this point, where someone manually has to go and click the "Enforce Ready Entities" button. That sounds like a minor thing to do, but in an Enterprise it includes change control/PVT etc to do... ...but automating this out as a fortnightly thing should reduce risk and I can do other things. So I am comfortable with the API, but looking at v13/v14 API I dont see a functionality that can do this for me. Has anyone done this last step to fully utomate attack signature updates ?Solved2.6KViews1like11CommentsNamecheap and BIG-IP Integration via API
The script below will be attached to an EAV monitor, which is linked to a dummy pool. The script is designed to monitor F5XC DNSaaS (which is the current Authoritative DNS) and check if it can resolve DNS queries. If it cannot, the script will trigger an API call to Namecheap (our domain registrar) to change the nameservers back to Primary BIG-IP DNS. Simultaneously, the script will update the domain's NS records from F5XC to BIG-IP. #!/bin/sh # Define variables pidfile="/var/run/$MONITOR_NAME.$1.$2.pid" statusfile="/var/run/dns_status" check_string="RESPONSE-OK" # NAMECHEAP API USER API_USER="sampleapiuser" # NAMECHEAP APIKEY API_KEY="<apikey>" # NAMECHEAP ACCOUNT USERNAME USERNAME="namecheapuser1" # NAMECHEAP COMMAND TO CHANGE THE NAMESERVER COMMAND="namecheap.domains.dns.setCustom" # NAMECHEAP ALLOWED API CLIENT IP, WE SET IT TO BIG-IP IP CLIENT_IP="13.213.88.106" # SECOND LEVEL DOMAIN SLD="f5sg" # TOP LEVEL DOMAIN TLD="com" F5XC_NAMESERVERS="ns1.f5clouddns.com,ns2.f5clouddns.com" BIGIP_NAMESERVERS="gtm1.f5sg.com,gtm2.f5sg.com" # BIGIP ADMIN PASSWORD ADMIN_PASS="XXXXXXX" # Function to update DNS to F5XC nameservers sendapi_xc() { #tmsh modify ltm virtual VS_APP2 enabled F5XC_API_URL="https://api.namecheap.com/xml.response?ApiUser=$API_USER&ApiKey=$API_KEY&UserName=$USERNAME&Command=$COMMAND&ClientIp=$CLIENT_IP&SLD=$SLD&TLD=$TLD&NameServers=$F5XC_NAMESERVERS" curl -X GET "$F5XC_API_URL" >/dev/null 2>&1 } # Function to update DNS to BIGIP nameservers sendapi_bigip() { #tmsh modify ltm virtual VS_APP2 disabled BIGIP_API_URL="https://api.namecheap.com/xml.response?ApiUser=$API_USER&ApiKey=$API_KEY&UserName=$USERNAME&Command=$COMMAND&ClientIp=$CLIENT_IP&SLD=$SLD&TLD=$TLD&NameServers=$BIGIP_NAMESERVERS" curl -X GET "$BIGIP_API_URL" >/dev/null 2>&1 } # Functions to manage zone records using F5 iControl REST API addzr_xc() { curl -sku admin:$ADMIN_PASS "https://127.0.0.1:8443/mgmt/tm/util/bash" -X POST -H "Content-Type: application/json" -d "{\"command\":\"run\",\"utilCmdArgs\":\"-c 'echo arr external f5sg.com. f5sg.com. 50 NS ns1.f5clouddns.com. | zrsh'\"}" >/dev/null 2>&1 curl -sku admin:$ADMIN_PASS "https://127.0.0.1:8443/mgmt/tm/util/bash" -X POST -H "Content-Type: application/json" -d "{\"command\":\"run\",\"utilCmdArgs\":\"-c 'echo arr external f5sg.com. f5sg.com. 50 NS ns2.f5clouddns.com. | zrsh'\"}" >/dev/null 2>&1 } delzr_bip() { curl -sku admin:$ADMIN_PASS "https://127.0.0.1:8443/mgmt/tm/util/bash" -X POST -H "Content-Type: application/json" -d "{\"command\":\"run\",\"utilCmdArgs\":\"-c 'echo drr external f5sg.com. f5sg.com. 50 NS gtm1.f5sg.com. | zrsh'\"}" >/dev/null 2>&1 curl -sku admin:$ADMIN_PASS "https://127.0.0.1:8443/mgmt/tm/util/bash" -X POST -H "Content-Type: application/json" -d "{\"command\":\"run\",\"utilCmdArgs\":\"-c 'echo drr external f5sg.com. f5sg.com. 50 NS gtm2.f5sg.com. | zrsh'\"}" >/dev/null 2>&1 } addzr_bip() { curl -sku admin:$ADMIN_PASS "https://127.0.0.1:8443/mgmt/tm/util/bash" -X POST -H "Content-Type: application/json" -d "{\"command\":\"run\",\"utilCmdArgs\":\"-c 'echo arr external f5sg.com. f5sg.com. 50 NS gtm1.f5sg.com. | zrsh'\"}" >/dev/null 2>&1 curl -sku admin:$ADMIN_PASS "https://127.0.0.1:8443/mgmt/tm/util/bash" -X POST -H "Content-Type: application/json" -d "{\"command\":\"run\",\"utilCmdArgs\":\"-c 'echo arr external f5sg.com. f5sg.com. 50 NS gtm2.f5sg.com. | zrsh'\"}" >/dev/null 2>&1 } delzr_xc() { curl -sku admin:$ADMIN_PASS "https://127.0.0.1:8443/mgmt/tm/util/bash" -X POST -H "Content-Type: application/json" -d "{\"command\":\"run\",\"utilCmdArgs\":\"-c 'echo drr external f5sg.com. f5sg.com. 50 NS ns1.f5clouddns.com. | zrsh'\"}" >/dev/null 2>&1 curl -sku admin:$ADMIN_PASS "https://127.0.0.1:8443/mgmt/tm/util/bash" -X POST -H "Content-Type: application/json" -d "{\"command\":\"run\",\"utilCmdArgs\":\"-c 'echo drr external f5sg.com. f5sg.com. 50 NS ns2.f5clouddns.com. | zrsh'\"}" >/dev/null 2>&1 } # Manage the PID file to ensure only one instance of the script runs if [ -f $pidfile ]; then kill -9 -`cat $pidfile` > /dev/null 2>&1 fi echo "$$" > $pidfile # Run dig command and store the output in a variable response=$(dig @ns1.f5clouddns.com f5sg.com TXT +short) # Compare response and take action if echo "$response" | grep -q "$check_string"; then previous_status=$(cat "$statusfile" 2>/dev/null) if [ "$response" != "$previous_status" ]; then sendapi_xc addzr_xc delzr_bip fi echo "up" echo "$response" > "$statusfile" else previous_status=$(cat "$statusfile" 2>/dev/null) if [ "$response" != "$previous_status" ]; then sendapi_bigip addzr_bip delzr_xc fi echo "$response" > "$statusfile" fi rm -f "$pidfile"79Views0likes0CommentsBIG-IP Wide-IP to F5XC DNSLB converter
This is a conceptual sample script that converts BIG-IP Wide-IP records to F5XC DNSLB records. This bash script can be run using a cron job to check for configuration changes and synchronize them to F5XC. We used the F5XC API to post and update the configuration. You need to get an APIToken from your F5XC tenant and change the value on the POST commands on the script below. Note: Since this is not a full-blown converter script, it is limited to handling only a single Wide-IP pool member. You need to configure a GTM pool to include the IP addresses that need to be load balanced. Check the main article for more details. #!/bin/bash # Get list of wide IPs wideip_output=$(tmsh list gtm wideip all-properties one-line) # Get list of Pool pool_output=$(tmsh list gtm pool a one-line all-properties) # Declare associative arrays declare -A wideip_list declare -A current_wideip_info declare -A zone_array declare -A subdomain_info declare -A a_record_per_zone declare -A pool_list declare -A membersip_array # Unset variables function unset_arrays { unset current_wideip_info name subdomain domain type aliases description status failure_rcode last_resort_pool load_balancing_decision_log metadata minimal_response partition persist_cidr_ipv4 persist_cidr_ipv6 persistence pool_lb_mode pools pool_cname topology_edns0 ttl_persistence poolnames poolnames_array zone_array subdomain_info a_record_per_zone dnslb_name pool_list membersip_array } # Print wide IP details function print_wideip { for wideip in "${!wideip_list[@]}"; do echo "Wide IP: $wideip, Details: ${wideip_list[$wideip]}" done } # Create Zone function create_zone { curl -X POST -H "Authorization: APIToken XXXXX" -H "Accept: application/json" -H "Access-Control-Allow-Origin: *" -H "x-volterra-apigw-tenant: cag-waap2023" -H "Content-Type: application/json" -d "{\"metadata\":{\"name\":\"$zone\",\"namespace\":\"system\"},\"spec\":{\"primary\":{\"allow_http_lb_managed_records\":true},\"default_soa_parameters\":{},\"dnssec_mode\":{},\"rr_set_group\":[],\"soa_parameters\":{\"refresh\":3600,\"expire\":0,\"retry\":60,\"negative_ttl\":0,\"ttl\":0}}}" https://cag-waap2023.console.ves.volterra.io/api/config/dns/namespaces/system/dns_zones } # Create DNSLB function create_dnslb { curl -X POST -H "Authorization: APIToken XXXXX" -H "Accept: application/json" -H "Access-Control-Allow-Origin: *" -H "x-volterra-apigw-tenant: cag-waap2023" -H "Content-Type: application/json" -d "{\"metadata\":{\"name\":\"$dnslbname\",\"namespace\":\"system\",\"labels\":{},\"annotations\":{},\"disable\":false},\"spec\":{\"record_type\":\"A\",\"rule_list\":{\"rules\":[{\"geo_location_set\":{\"tenant\":\"cag-waap2023-gwjvytud\",\"namespace\":\"system\",\"name\":\"geo-1\",\"kind\":\"geo_location_set\"},\"pool\":{\"tenant\":\"cag-waap2023-gwjvytud\",\"namespace\":\"system\",\"name\":\"$xcdnslbpoolname\",\"kind\":\"dns_lb_pool\"},\"score\":100}]},\"response_cache\":{\"disable\":{}}}}" https://cag-waap2023.console.ves.volterra.io/api/config/dns/namespaces/system/dns_load_balancers } # Loop through each line of output while IFS= read -r line; do pool_name=$(awk '{print $4}' <<< "$line") dnslbpool_name=$(echo "$pool_name" | sed 's/[^a-zA-Z0-9]/-/g; s/.*/\L&/') pool_type=$(awk '{print $3}' <<< "$line") lbmode=$(grep -o 'load-balancing-mode [^ ]*' <<< "$line" | awk '{print $2}') # Convert load_balancing_mode to lowercase if it is "ROUND_ROBIN" if [[ "$lbmode" == "round-robin" ]]; then lbmode="ROUND_ROBIN" elif [[ "$lbmode" == "static-persistence" ]]; then lbmode="STATIC_PERSIST" elif [[ "$lbmode" == "global-availability" ]]; then lbmode="PRIORITY" elif [[ "$lbmode" == "ratio" ]]; then lbmode="RATIO_MEMBER" fi # Extract members block using awk #members=$(awk -F 'members {| }' '{print $2}' <<< "$line") members=$(echo "$line" | grep -o -P '(?<=members \{ ).*?(?=\} \})') membernames=$(echo "$members" | grep -oP '\S+(?=\s*{)') # Temporary array to hold member IP addresses declare -a temp_members_array temp_members_array=($(awk -F ':' '{print $2}' <<< "$membernames")) monitor=$(awk -F 'monitor ' '{print $2}' <<< "$line" | awk '{print $1}') ttl=$(awk '{print $2}' <<< "$(grep -o 'ttl [^ ]*' <<< "$line")") # Assign values to the associative array membersip_array["$dnslbpool_name"]="${temp_members_array[@]}" # Store extracted values in the array pool_list["$dnslbpool_name"]="pool_type: $pool_type, lbmode: $lbmode, monitor: $monitor, members: ${membersip_array["$dnslbpool_name"]}, ttl: $ttl" done <<< "$pool_output" # Loop through each pool in the pool_list for dnslbpool_name in "${!pool_list[@]}"; do # Extract only the TTL value from the string ttl=$(awk -F 'ttl: ' '{print $2}' <<< "${pool_list[$dnslbpool_name]}") lbmode=$(awk -F 'lbmode: ' '{print $2}' <<< "${pool_list[$dnslbpool_name]}" | awk -F ',' '{print $1}') members=$(awk -F 'members: ' '{print $2}' <<< "${pool_list[$dnslbpool_name]}" | awk -F ',' '{print $1}') pool_type=$(awk -F 'pool_type: ' '{print $2}' <<< "${pool_list[$dnslbpool_name]}" | awk -F ',' '{print $1}') # Check if pool_type is "a" if [[ "$pool_type" == "a" ]]; then # Initialize an empty string to store the JSON strings members_string="" # Loop through each record in the current zone for ip in ${membersip_array["$dnslbpool_name"]}; do # Create JSON string for each member and append to the existing string members_string+="{\"ip_endpoint\":\"$ip\",\"ratio\":10,\"priority\":1}," done # Remove the trailing comma from the JSON string members_string="${members_string%,}" # Create DNSLB Pools curl -X POST \ -H "Authorization: APIToken Rs0aGJm/lda/JmbE00c9lFXWw4I=" \ -H "Accept: application/json" \ -H "Access-Control-Allow-Origin: *" \ -H "x-volterra-apigw-tenant: cag-waap2023" \ -H "Content-Type: application/json" \ -d "{\"metadata\":{\"name\":\"$dnslbpool_name\",\"namespace\":\"system\"},\"spec\":{\"a_pool\":{\"members\":[$members_string],\"disable_health_check\":null,\"max_answers\":1},\"ttl\":\"$ttl\",\"load_balancing_mode\":\"$lbmode\"}}" \ "https://cag-waap2023.console.ves.volterra.io/api/config/dns/namespaces/system/dns_lb_pools" fi done # Unset variables to free up memory unset pool_list membersip_array # Loop through each line of output while IFS= read -r line; do # Extracting specific details using awk and sed based on the current line name=$(echo "$line" | awk '{print $4}') dnslb_name=$(echo "$name" | sed 's/\./-/g') subdomain=$(echo "$name" | cut -d'.' -f1) domain=$(echo "$name" | sed 's/^[^.]*\.//') type=$(echo "$line" | awk '{print $3}') aliases=$(echo "$line" | grep -o 'aliases [^}]*' | awk '{print $2}') description=$(echo "$line" | grep -o 'description [^ ]*' | sed 's/description //') status=$(echo "$line" | awk '{print $12}') failure_rcode=$(echo "$line" | grep -o 'failure-rcode [^ ]*' | sed 's/failure-rcode //') last_resort_pool=$(echo "$line" | grep -o 'last-resort-pool [^ ]*' | sed 's/last-resort-pool //') load_balancing_decision_log=$(echo "$line" | grep -o 'load-balancing-decision-log-verbosity [^ ]*' | sed 's/load-balancing-decision-log-verbosity //') metadata=$(echo "$line" | grep -o 'metadata [^ ]*' | sed 's/metadata //') minimal_response=$(echo "$line" | grep -o 'minimal-response [^ ]*' | sed 's/minimal-response //') partition=$(echo "$line" | grep -o 'partition [^ ]*' | sed 's/partition //') persist_cidr_ipv4=$(echo "$line" | grep -o 'persist-cidr-ipv4 [^ ]*' | sed 's/persist-cidr-ipv4 //') persist_cidr_ipv6=$(echo "$line" | grep -o 'persist-cidr-ipv6 [^ ]*' | sed 's/persist-cidr-ipv6 //') persistence=$(echo "$line" | grep -o ' persistence [^ ]*' | sed 's/persistence //') pool_lb_mode=$(echo "$line" | grep -o 'pool-lb-mode [^ ]*' | sed 's/pool-lb-mode //') pools=$(echo "$line" | grep -o -P '(?<=pools \{ ).*?(?=\} \})') pool_cname=$(echo "$line" | grep -o 'pools-cname [^ ]*' | sed 's/pools-cname //') topology_edns0=$(echo "$line" | grep -o 'topology-prefer-edns0-client-subnet [^ ]*' | sed 's/topology-prefer-edns0-client-subnet //') ttl_persistence=$(echo "$line" | grep -o 'ttl-persistence [^ ]*' | sed 's/ttl-persistence //') # Use grep to find strings before "{" poolnames=$(echo "$pools" | grep -oP '\S+(?=\s*{)' | sed 's/[^a-zA-Z0-9]/-/g; s/.*/\L&/') # Convert matches to an array readarray -t poolnames_array <<< "$poolnames" # Store extracted values in the associative array current_wideip_info=([Type]="$type" [Subdomain]="$subdomain" [Domain]="$domain" [Status]="$status" [DNSLB]="$dnslb_name" [Pools]="${poolnames_array[@]}" [Pool_LB_Mode]="$pool_lb_mode") # Assign wideip_info to wideip_list wideip_list["$name"]="${current_wideip_info[@]}" # Add subdomains to zone_array if [ -n "${zone_array[$domain]}" ]; then zone_array["$domain"]="${zone_array[$domain]},$subdomain" else zone_array["$domain"]=$subdomain fi # Store subdomain information in subdomain_info array subdomain_info["$subdomain"]="${current_wideip_info[@]}" # Store subdomain type "a" and add it to the array for that zone if [ "$type" == "a" ]; then a_record_per_zone[$domain]="${a_record_per_zone[$domain]}${a_record_per_zone[$domain]:+,}$subdomain" fi done <<< "$wideip_output" for zone in "${!zone_array[@]}"; do create_zone done # Loop through each domain in a_record_per_zone and echo its A record subdomains for domain in "${!a_record_per_zone[@]}"; do echo "Domain: $domain" echo "A Record Subdomains: ${a_record_per_zone[$domain]}" echo "--------------------------" # Initialize an empty string to store the JSON strings a_records_string="" # Loop through each record in the current zone for record in ${a_record_per_zone[$domain]//,/ }; do # Create JSON string for each A record and append to the existing string xcdnslbpoolname=$(echo ${wideip_list[$record.$domain]} | awk '{for (i=6; i<=(NF-1); i++) {printf "%s", $i; if (i < NF-1) printf " "}}') #echo "${a_record_per_zone[$domain]}" #echo "xcdnslbpoolname: $xcdnslbpoolname" # Check if xcdnslbpoolname has multiple strings if [[ $xcdnslbpoolname == *" "* ]]; then echo "Multiple strings found in xcdnslbpoolname" # Split xcdnslbpoolname into an array based on space IFS=' ' read -ra pool_names <<< "$xcdnslbpoolname" # Initialize an empty string to store the JSON strings pools_string="" # Loop through each pool name in the array for pool_name in "${pool_names[@]}"; do # Create JSON string for each member and append to the existing string pools_string+="{\"geo_location_set\":{\"tenant\":\"cag-waap2023-gwjvytud\",\"namespace\":\"system\",\"name\":\"geo-1\",\"kind\":\"geo_location_set\"},\"pool\":{\"tenant\":\"cag-waap2023-gwjvytud\",\"namespace\":\"system\",\"name\":\"$pool_name\",\"kind\":\"dns_lb_pool\"},\"score\":100}," done # Remove the trailing comma from the JSON string pools_string="${pools_string%,}" else pools_string="{\"geo_location_set\":{\"tenant\":\"cag-waap2023-gwjvytud\",\"namespace\":\"system\",\"name\":\"geo-1\",\"kind\":\"geo_location_set\"},\"pool\":{\"tenant\":\"cag-waap2023-gwjvytud\",\"namespace\":\"system\",\"name\":\"$xcdnslbpoolname\",\"kind\":\"dns_lb_pool\"},\"score\":100}" fi dnslbname=$(echo "dnslb-$record-$domain" | sed 's/\./-/g') #create_dnslb curl -X POST -H "Authorization: APIToken XXXXX" -H "Accept: application/json" -H "Access-Control-Allow-Origin: *" -H "x-volterra-apigw-tenant: cag-waap2023" -H "Content-Type: application/json" -d "{\"metadata\":{\"name\":\"$dnslbname\",\"namespace\":\"system\",\"labels\":{},\"annotations\":{},\"disable\":false},\"spec\":{\"record_type\":\"A\",\"rule_list\":{\"rules\":[$pools_string]},\"response_cache\":{\"disable\":{}}}}" https://cag-waap2023.console.ves.volterra.io/api/config/dns/namespaces/system/dns_load_balancers a_records_string+="{\"ttl\":3600,\"lb_record\": {\"name\":\"$record\",\"value\":{\"namespace\": \"system\",\"name\":\"$dnslbname\"}}}," done # Remove the trailing comma from the JSON string a_records_string="${a_records_string%,}" # Print the final JSON string echo "$a_records_string" #update zone record curl -X PUT -H "Authorization: APIToken XXXXX" -H "Accept: application/json" -H "Access-Control-Allow-Origin: *" -H "x-volterra-apigw-tenant: cag-waap2023" -H "Content-Type: application/json" -d "{\"metadata\":{\"name\":\"$domain\",\"namespace\":\"system\"},\"spec\":{\"primary\":{\"allow_http_lb_managed_records\":true,\"default_rr_set_group\":[$a_records_string],\"default_soa_parameters\":{},\"dnssec_mode\":{},\"rr_set_group\":[],\"soa_parameters\":{\"refresh\":3600,\"expire\":0,\"retry\":60,\"negative_ttl\":0,\"ttl\":0}}}}" https://cag-waap2023.console.ves.volterra.io/api/config/dns/namespaces/system/dns_zones/$domain done unset_arrays125Views0likes0Comments