Close

Gaining Altitude with Python and APIs

By Richard McIntosh, Blog Contributor
Share Post

Drone

In a previous blog, Getting off the Ground with Python and APIs, we took a glance at the power of Python and APIs when it comes to automating your network. In this blog, we are going to take our configuration to the next level with additional user inputs to automate deploying a new WLAN secured using WPA2-PSK. First, we will revisit our existing script and change how we gather our required information from the end user. Next, we will apply the changes we want on our controller. Finally, we will run a show command to confirm our changes were successful.

The equipment I am using for this post is a 7005 Mobility Controller in standalone mode running ArubaOS 8.6. You can find the full script and requirements on GitHub.

Since we are doing a bit more than just adding a VLAN to a mobility controller, I think it would be a fine choice to have our Python script ask us questions instead of expecting a user to remember a ton of different arguments to pass from the command line. If you were planning on doing a lot of these deployments, it might make sense to keep the args in this script.  In our scenario where we are adding a single WLAN to a single controller, I thought it would be fun to show the different ways we can interact with our Python script.

First things first.  Let’s import the libraries we need and set urllib3 to suppress error messages on mobility controllers without certificates installed.

  1. import requests
  2. import json
  3. import urllib3
  4. from getpass import getpass
  5. # Suppress error messages for controllers without SSL certificates
  6. disable_warnings(urllib3.exceptions.InsecureRequestWarning)

In this next step, we will ask our user to input the values needed by the script later on.  In our previous blog, we used arguments passed from the command line.  You’ll notice in this script we also verify the user enters the same controller password and pre-shared key (PSK) using the getpass library.

  1. # Collect user input for our script
  2. ip = input("Enter the IP Address of your Controller: ")
  3. username = input("Controller Username: ")
  4. password = None
  5. whilenot password:
  6. password = getpass('Controller Password: ')
  7. password_verify = getpass('Retype your password: ')
  8. if password != password_verify:
  9. print('Passwords do not match.  Try again.')
  10. password = None
  11. ssid_name = input("New SSID Name: ")
  12. presharedkey = None
  13. whilenot presharedkey:
  14. presharedkey = getpass('Enter the PSK for this WLAN: ')
  15. presharedkey_verify = getpass('Retype your PSK: ')
  16. if presharedkey != presharedkey_verify:
  17. print('PSKs do not match.  Try again.')
  18. presharedkey = None
  19. vlan = input("Assign to a VLAN: ")

In our next section we will log into the controller, using the previously provided IP address, username, and password.  From here we are able to retrieve the UID we will use in our API calls and to set our cookie value that allows us access to the controller’s API.  You’ll notice in later sections that we continually reference uid and cookies values.

  1. # Log into Aruba Controller and retrieve UIDARUBA for API access
  2. r = requests.get(url='https://'+ ip + ':4343/v1/api/login?username=' \
  3. + username +'&password='+ password, verify=False)
  4. logindata = r.json()
  5. uid = logindata['_global_result']['UIDARUBA']
  6. cookies = {'SESSION': uid}
  7. headers = {'content-type': 'application/json'}
  8. print("Our UID for this sessions is: "+ uid + '\n')

Next, we are taking the inputs that our user provided during the beginning of the script and applying the requested changes to our controllers.

In order we will:

  1. Create a new VLAN
  2. Build a AAA profile
  3. Build an Auth profile
  4. Build a SSID profile
  5. Build a Virtual AP
  6. Add the new SSID to the Default AP group
  7. Save the configuration to the controller

Note: When sending values such as true and false you need to use the Boolean value. For example, when configuring the opmode to wpa2-psk-aes you will need to enter bool(‘true’) instead of a string value that we use in other locations such as the profile names.

When this portion of the script runs you will receive the full JSON response from the controller.  This can be changed by simply removing .text at the end of each print statement. The great part of keeping the full response is the ability to troubleshoot any problems that may have occurred. If you were to change a role in the AAA profile, for example, you may see an output similar to:  "status_str": "Error: Role ‘example’ is user defined and can't be applied without Next Generation Policy Enforcement Firewall”.

  1. # Create a new VLAN
  2. print("\nCreating VLAN \n")
  3. newvlan = {'id': vlan}
  4. post_vlan_id = requests.post(url='https://'+ ip + \
  5. ":4343/v1/configuration/object/vlan_id?config_path=%2Fmm&UIDARUBA="+ uid, \
  6. data=json.dumps(newvlan), headers=headers, verify=False, cookies=cookies)
  7. print(post_vlan_id.text)
  8. # Build AAA Profile
  9. print("\nCreating Authentication Profiles \n")
  10. dot1x_prof = {
  11. "profile-name": ssid_name + "_auth_prof"
  12. }
  13. post_dot1x_prof = requests.post(url='https://'+ ip + \
  14. ":4343/v1/configuration/object/dot1x_auth_profile?config_path=%2Fmm&UIDARUBA="\
  15. + uid, data=json.dumps(dot1x_prof), headers=headers, verify=False, \
  16. cookies=cookies)
  17. print(post_dot1x_prof.text)
  18. aaa_prof = {
  19. "profile-name": ssid_name + "_aaa_prof",
  20. "default_user_role": {
  21. "role": "logon"
  22. },
  23. "dot1x_auth_profile": {
  24. "profile-name": ssid_name + "_auth_prof"
  25. },
  26. }
  27. post_aaa_prof = requests.post(url='https://'+ ip + \
  28. ":4343/v1/configuration/object/aaa_prof?config_path=%2Fmm&UIDARUBA="+ uid, \
  29. data=json.dumps(aaa_prof), headers=headers, verify=False, cookies=cookies)
  30. print(post_aaa_prof.text)
  31. # Build SSID profile
  32. print("\nCreating SSID Profile \n")
  33. ssid_prof = {
  34. "profile-name": ssid_name + "_ssid_prof",
  35. "ssid_enable": {
  36. "_present": bool('true'),
  37. "_flags": {
  38. "default": bool('true')
  39. }
  40. },
  41. "essid": {
  42. "essid": ssid_name
  43. },
  44. "wpa_passphrase": {
  45. "wpa-passphrase": presharedkey
  46. },
  47. "opmode": {
  48. "wpa2-psk-aes": bool('true'),
  49. },
  50. }
  51. post_ssid_prof = requests.post(url='https://'+ ip + \
  52. ":4343/v1/configuration/object/ssid_prof?config_path=%2Fmm&UIDARUBA="+ uid, \
  53. data=json.dumps(ssid_prof), headers=headers, verify=False, cookies=cookies)
  54. print(post_ssid_prof.text)
  55. # Build Virtual AP
  56. print("\nCreating Virtual AP \n")
  57. virtual_ap_prof = {
  58. "profile-name": ssid_name,
  59. "aaa_prof": {
  60. "profile-name": ssid_name + "_aaa_prof"
  61. },
  62. "vlan": {
  63. "vlan": vlan
  64. },
  65. "forward_mode": {
  66. "forward_mode": "tunnel"
  67. },
  68. "ssid_prof": {
  69. "profile-name": ssid_name + "_ssid_prof"
  70. }
  71. }
  72. post_virtual_ap_prof = requests.post(url='https://'+ ip + \
  73. ":4343/v1/configuration/object/virtual_ap?config_path=%2Fmm&UIDARUBA="+ uid, \
  74. data=json.dumps(virtual_ap_prof), headers=headers, verify=False, cookies=cookies)
  75. print(post_virtual_ap_prof.text)
  76. # Add to Default AP Group
  77. print("\nAdding new WLAN to Default AP Group \n")
  78. ap_group_prof = {
  79. "profile-name": "default",
  80. "virtual_ap": [
  81. {
  82. "profile-name": ssid_name
  83. }
  84. ]
  85. }
  86. headers = {'content-type': 'application/json'}
  87. post_ap_group_prof = requests.post(url='https://'+ ip + \
  88. ":4343/v1/configuration/object/ap_group?config_path=%2Fmm&UIDARUBA="+ uid, \
  89. data=json.dumps(ap_group_prof), headers=headers, verify=False, cookies=cookies)
  90. print(post_ap_group_prof.text)
  91. # Save the Configuration
  92. print("\nSaving Configuration \n")
  93. write_memory = requests.post(url='https://'+ ip + \
  94. ':4343/v1/configuration/object/write_memory?config_path=%2Fmm&UIDARUBA='+uid, \
  95. headers=headers, verify=False, cookies=cookies)
  96. print(write_memory.text)

I’ve omitted the output of this portion, because it is a couple pages worth of output.  As I previously mentioned, use this output in your troubleshooting and verification process.

Finally, we verify that the script ran successfully, and our new WLAN has been created. From the output below you are able to determine that we created a WLAN called New-WLAN, it uses WPA2-PSK-AES encryption, and it uses VLAN 1 for data traffic.

  1. # Show the new WLAN
  2. print("\nShow AP ESSID\n")
  3. show_ap_essid = requests.get(url='https://'+ ip + \
  4. ':4343/v1/configuration/showcommand?json=1&command=show+ap+essid&UIDARUBA='\
  5. +uid, headers=headers, verify=False, cookies=cookies)
  6. print(show_ap_essid.text)

Show AP ESSID

Congratulations! You have just created a WLAN from scratch using Python and the APIs on the Aruba Mobility Controller. What other tasks do you think you could automate? Join in on the Airheads Developer Community and see what others are doing in their environments. I also encourage you to check out Brian Gleason’s blog series about building a lab. He has a lot of information around building a lab that best suits you and your needs.

Read My Other Blogs

Getting off the Ground with Python and APIs

Cybersecurity in a Zero Trust Architecture

Intelligent Networks Require Intelligent Solutions

IoT Security and Pre-Shared Keys