Cisco ASA REST API – Part V: Node.js, JavaScript and small HTTP server displaying ACL
I was not planning this chapter and putting away Perl for even a moment, but I have some talk with my VeriFone colleague on scripting, REST API and how creating web server which uses REST API back end to control certain parameters of firewall is not that easy and straightforward. We both have some programming and scripting experience but neither of us is a programmer. We both know more or less several programming languages but we are not proficient. But we both have (at least we thing we have) good fundamental knowledge about programming.
The topic circulated around web page that will let display and manipulate ACL entries on firewall in non-SDN data center. Feature quite simple that most independent firewall management platforms can do. The problem is that most of those applications are using CLI via SSH to send commands and parse output, that’s exactly how Cisco ASDM is working in example, but we wanted something maybe a little more flexible, reliable… We both agreed that JSON is flexible structure that should be easy to use. So how to write a comprehensive script?
Idea for test script is that it will display both on console and web page list of objects allowed on incoming ACL on predefined interface. This action will be triggered when someone connects to HTTP server. Ideas that came to my mind are:
- Apache2 with some back end script in Perl using mod_perl plugin
- Serving web server and all content via web server handled by scripting language
Both of the solutions have good and bad sides. In first case I’ve never been using mod_perl
and biggest problem I see is how to pass arguments, forms etc. from web page to script (I assume that script displaying it’s results as HTML or form should be easier). In second case I’ve never been programming using JavaScript but I assumed that node.js and JavaScript itself should have all required tools not that hard to use. So I decided to give it a try. After all even built-in REST API documentation uses JavaScript to execute methods!
After first shock…
As I mentioned I’m not a programmer but I had my experience with bash, perl, C, C++, C#, VisualBasic, PHP and Java. I thought JavaScript should be somehow like Java. That assumption was wrong! I was able to understand basics just by looking at examples but JavaScript and classic Java are two different worlds for me.
As I used to learn and write applications in C and C++ mostly in the past the syntax construction was not straightforward for me. It’s not JavaScript course so I won’t get into details. Enough said way of nesting functions and executing methods is not very clear and official documentation I found not really helpful.
I moved on and started some tests which results in presented script. I think it’s quite simple in it’s logic:
Web server is listening for connections on port 8080. When someone connects if will fetch ACL attached to interface lxc-sshd-5
and display all objects permitted as source on this interface both on console and web page.
To run this we will need node.js installed which is not hard thing to do. All instructions and latest packages for multiple platforms are available on Node.js website. You will wide documentation there as well.
Connecting to REST API from JavaScript
REST API documentation consist of many examples of methods in JavaScript. I used it as a template for my script and removed option to provide own username and password. All parameters like username, password, executed method, URI which includes interface name are hard-coded.
To open connection function https.request()
is executed. Response header is displayed on console – no error handling is deployed in this script.
HTTPS client operates on callback function that is fed by variable containing everything that HTTPS server, in our case it’s ASA, sends back to client. This variable is named res in this example. HTTPS server can also result several events (it’s displayed in Node.js documentation). We will focus on two of those named 'data'
and 'end'
.
First one returns chunk of data. Because returned value can be big in size it’s dividend into chunks that we have to concatenate by ourselves. I had some problems in coding this, mostly because by not knowing about handling asynchronous connections and returned data. During my attempts I got unformatted JSON object that I was not able to further format or buffer type of data that looks completely unusable:
Buffer 7b 22 6b 69 6e 64 22 3a 22 6f 62 6a 65 63 74 23 43 6c 6f 63 6b 22 2c 22 73 65 6c 66 4c 69 6e 6b 22 3a 22 68 74 74 70 73 3a 2f 2f 31 37 32 2e 31 36 2e ... >
But what we really want to get in response is called ExtendedACE. This object can be nested so in response one ExtendedACE can contain other items of that type. Full description is available in REST API documentation on any firewall running REST API (check Cisco ASA REST API – Part I: Getting started post). Mandatory ones are marked.
To be honest I don’t know if presented method is optimal, safe, but at least it’s working
// This array will be used to store JSON response var JSON_ExtendedACE = []; // In asynchronous mode push method is used to update result string res.on('data', function(d) { // When any chunk of data is received it will be added // To JSON_ExtendedACE array JSON_ExtendedACE.push(d); });
Second even is 'end'
and as it’s name suggest it means that connection to HTTPS server is closed. At this stage we have all data and we can parse it
Parsing JSON in JavaScript
JSON came from JavaScript world. So I must say when you understand what operations you need to do and how it will be quite straightforward to refer to interested values. Just remember that JSON objects can be nested (also in arrays of JSON objects) and it’s structure is not static.
By using function JSON.parse()
we can convert an array to JSON structure. When we do that we can easily refer to objects by names. It’s making code easier to read in my opinion and it’s easy to refer to particular value if we know JSON structure we are using.
Code below is valuable in one more way – not may examples on Internet cover multi layer JSON structures. In our example the we have array of 'item'
JSON objects which will differ in types. So first we execute ForEach()
method on ‘items’ then by ‘if’ we are determining which value of nested JSON object we display. ForEach()
can be replaced by /code>’for’ or 'while'
loops but this approach is much more efficient and cleraner for the code.
To refer to particular value we just refer it by using it’s name, of course remembering about structure of JSON variable.
// This will execute when all data is received res.on('end', function() { // Received array is oparsed into JSON structure var JSONStructure = JSON.parse(JSON_ExtendedACE); // HTML headers wrote to our HTTP server output response.write('<html><body>'); // Response recorded in JSON consist of multiple items so we // process each item separately JSONStructure.items.forEach(function(item) { // Each item can have different structure so we process it // by displaying different values if (item.sourceAddress.objectId) { // If item have "objectId" field we will display it // It's for entries like object or object-group console.log(item.sourceAddress.objectId); response.write(item.sourceAddress.objectId + '<br>'); } else if (item.sourceAddress.value) { // If item is just IP address we will display it console.log(item.sourceAddress.value); response.write(item.sourceAddress.value + '<br>'); } }); // Closing HTML headers response.write('</body></html>'); // Closing HTTP pipe to client response.end(); });
HTTP server for incoming requests
Last part is our own HTTP server used for handling incoming requests. Many developers says that using 'express'
HTTP server available as external library is much easier but for this example built-in one is sufficient.
// Create Server (listen port defined at the end) HTTPServer.createServer(function(request, response) {
[...]
}).listen(8080); // Definition of listening port
Yes, that’s all. Inside we put all the code for REST API, at the end we define listening port.
Running script
Of you remember description of initial configuration of my lab (check Cisco ASA REST API – Lab topology and programming language) no ACLs are defined by default. For purpose of this test access-list lxc-sshd-5_access_in
is added to interface lxc-sshd-5
. Access list contain three types of objects defined as Source IP Address – object, object-group and IP Address.
object network TEST_1_10.88.88.1 host 10.88.88.1 object network TEST_2_10.88.88.2 host 10.88.88.2 object-group network GROUP_TEST network-object host 10.66.66.1 network-object host 10.66.66.2 access-list lxc-sshd-5_access_in extended permit ip object TEST_1_10.88.88.1 any access-list lxc-sshd-5_access_in extended permit ip object TEST_2_10.88.88.2 any access-list lxc-sshd-5_access_in extended permit ip host 10.77.77.1 any access-list lxc-sshd-5_access_in extended permit ip host 10.77.77.2 any access-list lxc-sshd-5_access_in extended permit ip object-group GROUP_TEST any access-list lxc-sshd-5_access_in extended permit ip any any ! access-group lxc-sshd-5_access_in in interface lxc-sshd-5
Script and built-in HTTP server is started from command line
$ node listACL-1.js
If no error or command prompt is displayed our servers is running. Now we can connect via web broser to http://127.0.0.1:8080
.
Let’s first look at terminal. We can see information about execution statusCode
and headers that has been passed to firewall. We left this output in our script. Below the line we see six entries representing objects configured as source of traffic.
TEST_1_10.88.88.1 TEST_2_10.88.88.2 10.77.77.1 10.77.77.2 GROUP_TEST any
If we look at web browser same list is available and displayed as static web page.
And to sum everything up final look at HTML code we generated
<html><body>TEST_1_10.88.88.1 TEST_2_10.88.88.2 10.77.77.1 10.77.77.2 GROUP_TEST any</body></html>
Summary
Script itself is very simple, does not contain any forms and we only handle existing structure of JSON object. I have mixed feelings about using JavaScript for this for now. Maybe different next step should be learning Python?
Code of the script is available on GitHub.