Note: I may receive commissions for purchases made through links in this post. This is to help support my blog and does not have any impact on my recommendations.
This guide is written for CentOS 7. If you’re running another distro, find your dependencies here
Last year we had to begin migrating off of some of our older Juniper SSG firewalls since we were beginning to push them to their throughput limits. We evaluated a couple of vendors but ultimately decided to stay with Juniper and purchase SRX 1500 firewalls, which are capable of up to 10G throughput. After a while of working with these firewalls, I have to say they’re pretty solid devices and I’m extremely happy with them. One of the main reasons I like them so much is the ease of automation, which is what we’re going to dive into today. If you need a device for lab/test – Amazon has the SRX 300 for less than $300. I’ll likely be picking one up in the near future for easier automation testing.
Juniper provides an awesome library for SRX management called PyEZ. Here is what we need to get the toolkit ready to use in our scripts:
- Install dependencies – I run CentOS here, so I just needed to grab the following packages:
- yum -y install python-devel libxml2-devel libxslt-devel gcc openssl openssl-devel libffi-devel
- Just a quick note – Juniper’s web page doesn’t actually mention openssl-devel, but their tools will fail to install without it
- Get pip – If you don’t have it already, then download the pip installer here. Then just run the following:
- python get-pip.py
- Install PyEZ – Once everything else is set, this is the easy part:
- pip install junos-eznc
After all that is done, we can get to the exciting part: automating something so you don’t have to do it anymore! So here is what we’re going to throw in our script just to get started:
# Import the JunOS modules we need
from jnpr.junos import Device
# Define the login credentials and address for the target firewall
# Need to provide device address, user account, and password
# Note: Juniper also provides authentication via key-pair, which would be more secure than username/password
srx = Device('10.10.10.10', user='deviceuser', pass='devicepass')
# Open the connection
srx.open()
Once you have that going, it’s pretty easy to start making calls to collect data or change the configuration. In one of the first projects I used this for, I was making use of the API to reset VPN tunnels. This was due to an issue with a cross-vendor tunnel, which would occasionally break during VPN re-keys and only negotiate a uni-directional tunnel. So the script was written to detect a uni-directional flow of traffic, then log into the SRX and reset the VPN – which would force a renegotiation and fix the issue.
So in order to accomplish the SRX-side of that script, I used the following to reset the IKE and IPSec security associations:
# Clear IKE security association for a given peer
response = srx.rpc.clear_ike_security_association(peer_address='20.20.20.20')
# Check to see if command was accepted
if response == True: print "IKE SA Cleared"
# Clear IPSec security association for a given peer
# Note: In this case, you need to provide the index ID.
# Get the index ID from running 'show security ipsec sa' on the SRX
response = srx.rpc.clear_ipsec_security_association(index='123456')
# Same thing - Check to make sure the command succeeded
if response == True: print "IPSec SA Cleared"
This provides a pretty basic example of how easy it is to control the SRX via a Python script. You might be wondering: This is great, but how do I find the names of those calls? Well, Juniper made that extremely simple as well! Just take any command on the SRX and pipe it through display xml rpc and the device will tell you exactly what you need. For example:
root@SRX123> show security ipsec sa | display xml rpc
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/15.1X49/junos">
<rpc>
<get-security-associations-information>
</get-security-associations-information>
</rpc>
<cli>
<banner>{primary:node0}</banner>
</cli>
</rpc-reply>
In this case, we are running the command which would normally print all of the connected IPSec tunnels. So the section under rpc is where we want to look. Now just take the get-security-associations-information, and change the dashes to underscores. So to use this in a script we would call srx.rpc.get_security_associations_information(). I’ve actually used this command to build a VPN status dashboard using Python and Django, which I accomplished by just pulling all the IPSec tunnels and parsing them into a web table.
As a final note, I would highly recommend creating a separate service account on the SRX for scripting. A separate user account with limited permissions would be the recommended way to go here. It might seem like a pain to set up, but it’s worth it in terms of security. Here is what I have configured on my SRX firewalls for the API service account:
system {
login {
class api-class {
permissions security-control;
allow-commands "(clear security ike)|(clear security ipsec)";
deny-commands "(clear)|(file)|(file show)|(help)|(load)|(monitor)|(op)|(request)|(save)|(set)|(start)|(test)";
}
user apiuser {
full-name API_Service_Acct;
uid 125;
class api-class;
authentication {
encrypted-password <encrypted string here>
}
}
}
}
So using the above example, you should only define the necessary commands in the allow-commands section. If the account is ever compromised, we are severely limiting the amount of damage that could be done. A little extra effort, but potentially a big payoff.
So what did you think of this tutorial? Helpful? Have questions? Let me know in the comments below!