Category Archives: NFV

Cisco ASAv firewall REST API: Bulk Requests

Introduction

Continuing on the same track with ASA REST API we are going to explore how to be more efficient when firing up the json code toward our firewalls. In previous example we created a small number of service and network objects and groups, today we are going to experiment with larger number of objects created by smaller number of calls. Lets get the ball rolling.

Bulk service object creation

To create a bulk request we need to adjust some parameters such as API endpoint URL. As you recall, when we created a new service object we were pointing to this URL: https://<management-ip>/api/objects/networkservices.

Now we are going to redesign the call a little bit and will always point to same endpoint regardless of object type. We will simply use https://<management-ip>/api and the more specific resource URI will be part request body. This allows us for example create bulk of service and network objects in one call.

[
  {
    "resourceUri": "/api/objects/networkservices",
    "data": {     
  "kind": "object#TcpUdpServiceObj",
  "name": "TCP-21",
  "value": "tcp/21"
}, "method": "Post" }, { "resourceUri": "/api/objects/networkservices",    "data": {
  "kind": "object#TcpUdpServiceObj",
  "name": "TCP-22",
  "value": "tcp/22"
}, "method": "Post" }, { "resourceUri": "/api/objects/networkservices",    "data": {
  "kind": "object#TcpUdpServiceObj",
  "name": "TCP-23",
  "value": "tcp/23"
}, "method": "Post" }, { "resourceUri": "/api/objects/networkservices", "data": {
  "kind": "object#TcpUdpServiceObj",
  "name": "TCP-24",
  "value": "tcp/24"
}, "method": "Post" }
]

If everything is hunky dory you will receive a Status Code 200 OK and response body will contain additional details.

{
"entryMessages":
[
     {
     "resourceUri":"/api/objects/networkservices",
     "method":"POST",
     "selfLink":"http://10.201.230.5/api/objects/networkservices/TCP-21",
     "messages":
     [
         {
         "level":"Info",
         "code":"201",
         "details":"Created (201) - The request has been fulfilled and resulted in a new resource being created"
          }
     ]
     },
     {
     "resourceUri":"/api/objects/networkservices",
     "method":"POST",
     "selfLink":"http://10.201.230.5/api/objects/networkservices/TCP-22",
     "messages":
     [
         {
         "level":"Info",
         "code":"201",
         "details":"Created (201) - The request has been fulfilled and resulted in a new resource being created"
         }
     ]
     },
     {
     "resourceUri":"/api/objects/networkservices",
     "method":"POST",
     "selfLink":"http://10.201.230.5/api/objects/networkservices/TCP-23",
     "messages":
     [
         {
         "level":"Info",
         "code":"201",
         "details":"Created (201) - The request has been fulfilled and resulted in a new resource being created"
         }
     ]
     },
     {
     "resourceUri":"/api/objects/networkservices",
     "method":"POST",
     "selfLink":"http://10.201.230.5/api/objects/networkservices/TCP-24",
     "messages":
     [
         {
         "level":"Info",
         "code":"201",
         "details":"Created (201) - The request has been fulfilled and resulted in a new resource being created"
         }
     ]
     }
],
"commonMessages":[]
}

Ideally your deployment script would examine the response and capture the self links that can be used to un-deploy this call. Also the message details are important to verify if objects were successfully created.

Now we are going to look at error handling by creating another request that will have one already existing object and one new in it.

[
  {
    "resourceUri": "/api/objects/networkservices",
    "data": {     
  "kind": "object#TcpUdpServiceObj",
  "name": "TCP-24",
  "value": "tcp/24"
}, "method": "Post" }, { "resourceUri": "/api/objects/networkservices", "data": {
  "kind": "object#TcpUdpServiceObj",
  "name": "TCP-25",
  "value": "tcp/25"
}, "method": "Post" }
]

The response header will contain 400 Bad Request status code and body will reveal some clues.

{
"entryMessages":
[
     {
     "resourceUri":"/api/objects/networkservices",
     "method":"POST",
     "messages":
     [
         {
         "level":"Error",
         "code":"DUPLICATE",
         "context":"objectId",
         "details":"TCP-24"
         }
     ]
     },
     {
     "resourceUri":"/api/objects/networkservices",
     "method":"POST"
     }
],
"commonMessages":[]
}

The result result is that even the second object did not exists it was not created. When you reverse the object order in request, it will not help either. This means that the entire request need to create unique objects otherwise it will fail. So watch for return codes.

I have tried to create 103 unique objects in one request and I have found that the upper limit for single request is 100 entries.

{
"commonMessages":
[
     {
     "level":"Error",
     "code":"MAX-ENTRIES-LIMIT-EXCEEDED",
     "details":"The number of entries found are, 103. The bulk entries limit:100"
     }
]
}

Lets go back to our first four service objects and undeploy them using four unique DELETE Requests. The resource URIs are as follows:

Note: So far I have not found way of performing multiple object removal in single request. It seems that bulk operation only supports POST method toward service objects at the moment. The following below did not work.

[
  {
    "resourceUri": "/api/objects/networkservices/TCP-21",
    "method": "Delete"
  },
  {
    "resourceUri": "/api/objects/networkservices/TCP-21",
    "method": "Delete"
  }
]

Response had status code 400 Bad Request even if those URI are indeed valid and you can query them with GET request.

{
"entryMessages":
[
     {
     "resourceUri":"/api/objects/networkservices/TCP-21",
     "method":"DELETE",
     "messages":
     [
         {
         "level":"Error",
         "code":"INVALID-INPUT",
         "details":"Invalid resourceUri:/api/objects/networkservices/TCP-21"
         }
     ]
     },
     {
     "resourceUri":"/api/objects/networkservices/TCP-21",
     "method":"DELETE",
     "messages":
     [
         {
         "level":"Error",
         "code":"INVALID-INPUT",
         "details":"Invalid resourceUri:/api/objects/networkservices/TCP-21"
         }
     ]
     }
],
"commonMessages":[]
}

The 100 objects limitations also affect how are the responses constructed. When you query the following resource https://<management-ip>/api/objects/networkservices you will see that the body contains only 100 items even if 110 exists. You can see this by examining the offset, limit and total fields on body.

{
   "kind": "collection#NetworkServiceObjects",
   "selfLink": "https://10.201.230.5/api/objects/networkservices",
   "rangeInfo":
   {
       "offset": 0,
       "limit": 100,
       "total": 110
   },

Funny enough, the list will not start with the first configure service objects, but started from TCP-100 up till TCP-200. To see other items you need to manipulate the offset value. We can demonstrate this using API Console at documentation page.

rest-api-offset

Now the item list will start from TCP-110 and will include our older objects such as TCP-21, TCP-22 etc. You can also play with the limit parameter to constrain number of returned objects. If you look at Inspector, you will see the request parameters have been modified to include our query parameters.

rest-api-offset-body

Conclusion

Bulk object creation and retrieval handling should help you build more efficient communication patters between the firewall and automation tool or network controller.

Advertisements

Cisco ASAv firewall HA Pair

Introduction

In previous post I have introduced and demonstrated the ASA in virtual form factor. This post will built on top of previous that one and will show you how to setup redundant high available pair of these firewalls.

The HA setup is ideal in situations where you are building virtual infrastructure hosted on private or public cloud that needs to be available all the time, surviving failure of one of the firewalls that run as virtual machines. Standard vSphere VM placement best practices should be also considered, such as anti-affinity rules and resource allocation. Consult these with you VMware administrators.

The following diagram outlines the final setup. My home lab only has one ESXi hosts, so everything is running over there.

ASAv HA Setup

Active Firewall rollout

Start with the deployment of first firewall which will be the active one. After downloading the OVA package from Cisco go to vSphere\Virtual Machines\Right Click on Cluster\Deploy OVF Template.

asav-ha-step1

After browsing and selecting the OVA package, I am using asav931.ova, you will be ask to accept the extra configuration options and estimated disk size requirements.

asav-ha-step2

Next, accept the license agreement and and click next. You will have an option to select the name of the new primary ASA which will be ASAv03-Active and the location of the VM.

asav-ha-step3

You will now have a choice to select deployment size, from 1vCPU Standalone all the way up to 4vCPU. If you are deploying in production, you should consult the deployment guide for the right flavor. I am deploying in lab, therefore I have selected 1vCPU HA Primary.

asav-ha-step4

After selecting the deployment size, we need to specify the resource that ASAv will consume. If you select a cluster DRS can automatically place the VM to least utilized hypervisor. You can also specify certain ESXi hosts. I have just one ESXi host, so the choice will be obvious.

asav-ha-step5

To same some storage space, change the default virtual disk format from Thick Provisioned to Thin Provision.

On the next page, we need to configure network mapping. ASAv has by default 10 vNIC adapters which first of them is the Management and the last Gig0/8 is used by HA Heartbeat. Remaining interfaces can be used for production traffic. We leave unused interface in DMZ for now.

asav-ha-step6

Now you have an option to Customize the template by typing configuration parameters such as Management Interface Settings, Device Manager IP Settings and HA Connection Settings.

The Management address of Primary Unit will be 172.16.2.1/24 and Secondary will be 172.16.2.2/24. The default gateway will not be required at this moment, our management station sits on the same virtual switch. To allow remote access from day 1, specify that the allowed management subnet is 172.16.2.0/24

The Primary Unit HA address will be 172.16.3.1/24 and the Secondary will be 172.16.3.2/24.

asav-ha-step7

In Ready to Complete page, you get the summary of all configuration options, and you will have a choice to Power VM after deployment. Congratulations you just deployed your first HA Pair Firewall. After first power on, ASAv will perform initial configuration and reboot.

If everything worked as expected, you should be able to log in from management station via SSH.

asav-ha-step8

By default, however, not username was configured in template therefore it is still needed to jump to virtual console and create one and point the AAA authentication for SSH to local user database.

It is also worth to mention that although ASDM https access was enable, it would still need to have an account and aaa authentication configured properly to work.

ciscoasa(config)# username admin password cisco privilege 15
ciscoasa(config)# enable password cisco
ciscoasa(config)# aaa authentication ssh console LOCAL

Now you can actually connect to the ASA remotely. If you examine the configuration a little bit you find that it has setup the failover interface and peer and currently shows that its mate is down/unknown.

ciscoasa# sh failover
Failover On
Failover unit Primary
Failover LAN Interface: fover GigabitEthernet0/8 (up)
Unit Poll frequency 1 seconds, holdtime 15 seconds
Interface Poll frequency 5 seconds, holdtime 25 seconds
Interface Policy 1
Monitored Interfaces 1 of 61 maximum
MAC Address Move Notification Interval not set
Version: Ours 9.3(1), Mate Unknown
Last Failover at: 10:16:56 UTC Feb 20 2015
        This host: Primary – Active
                Active time: 873 (sec)
                slot 0: empty
                  Interface management (172.16.2.1): Unknown (Waiting)
        Other host: Secondary – Failed
                Active time: 0 (sec)
                  Interface management (172.16.2.2): Unknown (Waiting)
 

ciscoasa# show failover state

State          Last Failure Reason      Date/Time
This host  –   Primary
Active         None
Other host –   Secondary
Failed         Comm Failure             10:17:13 UTC Feb 20 2015

====Configuration State===
====Communication State===

Standby Firewall rollout

Before we are going to configure the other interfaces, lets set up the secondary unit. Again we are going to start by deploying a template from .OVA. To save some space, I will only show difference from deploying the primary unit.

The VM name will be set to ASAv03-Standby, and the deployment configuration will be set to 1vCPU HA Secondary. Selecting the right resource in production should be also considered to minimize that a single hypervisor failure will cause both firewalls go down. Therefore I recommended anti-affinity rules so those two VMs will never run on same machine.

The interface mapping will be exactly same as with primary unit. See the reference above. In the customization template page, enter the Management IP address and HA IP address settings for this unit.

asav-ha-step9

Deployment of this small flavor took no longer than 30 seconds, and after the initial reboot the Standby firewall is up an running.

While still setting remotely on primary unit we are going to check the failover pair state again.

Beginning configuration replication: Sending to mate.
ciscoasa# show failover
Failover On
Failover unit Primary
Failover LAN Interface: fover GigabitEthernet0/8 (up)
Unit Poll frequency 1 seconds, holdtime 15 seconds
Interface Poll frequency 5 seconds, holdtime 25 seconds
Interface Policy 1
Monitored Interfaces 1 of 61 maximum
MAC Address Move Notification Interval not set
Version: Ours 9.3(1), Mate 9.3(1)
Last Failover at: 10:16:56 UTC Feb 20 2015
        This host: Primary – Active
                Active time: 2111 (sec)
                slot 0: empty
                  Interface management (172.16.2.1): Normal (Monitored)
        Other host: Secondary – Standby Ready
                Active time: 0 (sec)
                  Interface management (172.16.2.2): Normal (Waiting)

ciscoasa# sh failover state

               State          Last Failure Reason      Date/Time
This host  –   Primary
               Active         None
Other host –   Secondary
               Standby Ready  Comm Failure             10:17:13 UTC Feb 20 2015

====Configuration State===
        Sync Done
====Communication State===
        Mac set

====VM Properties Compatibility===
vCPUs – This host:  1
        Other host: 1
Memory – This host:  2048 Mhz
         Other host: 2048 Mhz
Interfaces – This host:  9
             Other host: 9

Looking much better now. To see failover in action, lets first complete the configuration of other interfaces to get some traffic flowing through the firewall

prompt hostname priority state
!
interface GigabitEthernet0/0
 description OUTSIDE
 nameif outside
 security-level 0
 ip address 10.0.2.91 255.255.255.0 standby 10.0.2.92
!
interface GigabitEthernet0/1
 description INSIDE
 nameif inside
 security-level 100
 ip address 172.16.0.1 255.255.255.0 standby 172.16.0.2
!
interface GigabitEthernet0/2
 description DMZ
 nameif dmz
 security-level 50
 ip address 172.16.1.1 255.255.255.0 standby 172.16.1.2
!
monitor-interface outside
monitor-interface inside
monitor-interface dmz
!
route outside 0 0 10.0.2.1
!
policy-map global_policy
 class inspection_default
  inspect icmp

My outside router does not have static routes to these private network behind ASA so a object NAT will help to mitigate that.

object network inside_net
 subnet 172.16.0.0 255.255.255.0
nat (inside,outside) source dynamic inside_net interface

Now we should have connectivity from inside host to Internet. We get verify that by pulling google web page from client and also checking the NAT or connection table.

ciscoasa# sh nat detail
Manual NAT Policies (Section 1)
1 (inside) to (outside) source dynamic inside_net interface
    translate_hits = 12, untranslate_hits = 0
    Source – Origin: 172.16.0.0/24, Translated: 10.0.2.91/24

Now start continuous ping from inside machine and power off the primary firewall.

root@deb01:~# ping -c 100 8.8.8.8
100 packets transmitted, 85 received, 15% packet loss, time 99250ms
rtt min/avg/max/mdev = 10.771/11.988/21.956/2.426

From the output, I examined that from 100 packets, 15 was lost during switchover. With default pool and hold times it was not amazingly fast. We can do better.

failover polltime unit 1 holdtime 3
failover polltime interface 1 holdtime 5

Repeat the 100 ping test again and examine the results.

Now with adjusted timers, from 100 packets we lost 4 during switchover. Getting better :-). Lets see how this HA pair will cope with TCP sessions.

We are going to initiate a large file download from inside host and then shutdown the secondary (now active) ASA and examine the result on traffic flow.

The primary ASA took back the role of Active Firewall, but the TCP session has died. There is one another parameter that we need to tweak for HTTP sessions and to explicitly enable them.

ciscoasa/pri/act(config)# failover replication http
Now initiate the download again, and check that it will be re-established after failover.

Conclusion

After tweaking some default settings you have a highly available firewall cluster running in fully visualized environment.

s