Tuesday, December 23, 2014

REST API for Cumulus Linux ACLs

RESTful control of Cumulus Linux ACLs included a proof of concept script that demonstrated how to remotely control iptables entries in Cumulus Linux.  Cumulus Linux in turn converts the standard Linux iptables rules into the hardware ACLs implemented by merchant silicon switch ASICs to deliver line rate filtering.

Previous blog posts demonstrated how remote control of Cumulus Linux ACLs can be used for DDoS mitigation and Large "Elephant" flow marking.

A more advanced version of the script is now available on GitHub:

https://github.com/pphaal/acl_server/

The new script adds the following features:
  1. It now runs as a daemon.
  2. Exceptions generated by cl-acltool are caught and handled
  3. Rules are compiled asynchronously, reducing response time of REST calls
  4. Updates are batched, supporting hundreds of operations per second
The script doesn't provide any security, which may be acceptable if access to the REST API is limited to the management port, but is generally unacceptable for production deployments.

Fortunately, Cumulus Linux is a open Linux distribution that allows additional software components to be installed. Rather than being forced to add authentication and encryption to the script, it is possible to install additional software and leverage the capabilities of a mature web server such as Apache. The operational steps needed to secure access to Apache are well understood and the large Apache community ensures that security issues are quickly identified and addressed.

This article will demonstrate how Apache can be used to proxy REST operations for the acl_server script, allowing familiar Apache features to be applied to secure access to the ACL service.

Download the acl_server script from GitHub
wget https://raw.githubusercontent.com/pphaal/acl_server/master/acl_server
Change the following line to limit access to requests made by other processes on the switch:
server = HTTPServer(('',8080), ACLRequestHandler)
Limiting access to localhost, 127.0.0.1:
server = HTTPServer(('127.0.0.1',8080), ACLRequestHandler)
Next, install the script on the switch:
sudo mv acl_server /etc/init.d/
sudo chown root:root /etc/init.d/acl_server
sudo chmod 755 /etc/init.d/acl_server
sudo service acl_server start
sudo update-rc.d acl_server start
Now install Apache:
sudo sh -c "echo 'deb http://ftp.us.debian.org/debian  wheezy main contrib' \
>>/etc/apt/sources.list.d/deb.list"
sudo apt-get update
sudo apt-get install apache2
Next enable the Apache proxy module:
sudo a2enmod proxy proxy_http
Create an Apache configuration file /etc/apache2/conf.d/acl_server with the following contents:
<ifmodule mod_proxy.c>
  ProxyRequests off
  ProxyVia off
  ProxyPass        /acl/ http://127.0.0.1:8080/acl/
  ProxyPassReverse /acl/ http://127.0.0.1:8080/acl/
</ifmodule>
Make any additional changes to the Apache configuration to encrypt and authenticate requests.

Finally, restart Apache:
sudo service apache2 restart
These above steps are easily automated using tools like Puppet or Ansible that are available for Cumulus Linux.

The following examples demonstrate the REST API.

Create an ACL

curl -H "Content-Type:application/json" -X PUT --data '["[iptables]","-A FORWARD --in-interface swp+ -d 10.10.100.10 -p udp --sport 53 -j DROP"]' http://10.0.0.233/acl/ddos1
ACLs are sent as a JSON encoded array of strings. Each string will be written as a line in a file stored under /etc/cumulus/acl/policy.d/ - See Cumulus Linux: Netfilter - ACLs. For example, the rule above will be written to the file 50rest-ddos1.rules with the following content:
[iptables]
-A FORWARD --in-interface swp+ -d 10.10.100.10 -p udp --sport 53 -j DROP
This iptables rule blocks all traffic from UDP port 53 (DNS) to host 10.10.100.10. This is the type of rule that might be inserted to block a DNS amplification attack.

Retrieve an ACL

curl http://10.0.0.233/acl/ddos1
Returns the result:
["[iptables]", "-A FORWARD --in-interface swp+ -d 10.10.100.10 -p udp --sport 53 -j DROP"]

List ACLs

curl http://10.0.0.233/acl/
Returns the result:
["ddos1"]

Delete an ACL

curl -X DELETE http://10.0.0.233/acl/ddos1

Delete all ACLs

curl -X DELETE http://10.0.0.233/acl/
Note this doesn't delete all the ACLs, just the ones created using the REST API. All default ACLs or manually created ACLs are inaccessible through the REST API.

The acl_server batches and compiles changes after the HTTP requests complete. Batching has the benefit of increasing throughput and reducing request latency, but makes it difficult to track compilation errors since they are reported later. The acl_server catches the output and status when running cl-acltool and attaches an HTTP Warning header to subsequent requests to indicate that the last compilation failed:
HTTP/1.0 204 No Content
Server: BaseHTTP/0.3 Python/2.7.3
Date: Thu, 12 Feb 2015 05:31:06 GMT
Accept: application/json
Content-Type: application/json
Warning: 199 - "check lasterror"
The output of cl-acltool can be retrieved:
curl http://10.0.0.233/acl/lasterror
returns the result:
{"returncode": 255, "lines": [...]}
The REST API is intended to be used by automation systems and so syntax problems with the ACLs they generate should be rare and are the result of a software bug. A controller using this API should check responses for the presence of the last error Warning, log the lasterror information so that the problem can be debugged, and finally delete all the rules created through the REST API to restore the system to its default state.

While this REST API could be used as a convenient way to manually push an ACL to a switch, the API is intended to be part of automation solutions that combine real-time traffic analytics with automated control. Cumulus Linux includes standard sFlow measurement support, delivering real-time network wide visibility to drive solutions that include: DDoS mitigation, enforcing black lists, marking large flows, ECMP load balancing, packet brokers etc.

1 comment:

  1. Awesome work as usual Peter. Happy Holidays!

    ReplyDelete